5

I've got the following chunk of XML data:

<ArrayOfRESTDataSource xmlns="http://SwitchKing.Common/Entities/RESTSimplified/2010/07" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<RESTDataSource>
    <Description>MyTest</Description>
    <Enabled>true</Enabled>
 </RESTDataSource>
</ArrayOfRESTDataSource>

RESTDataSource can occur 0-n times.

And here's my classes:

[DataContract( Namespace = "http://SwitchKing.Common/Entities/RESTSimplified/2010/07" )]
public class ArrayOfRESTDataSource
{
    public RESTDataSource[] Data { set; get; }  
}


[DataContract( Namespace = "http://SwitchKing.Common/Entities/RESTSimplified/2010/07" )]
public class RESTDataSource
{
    [DataMember]
    public bool Enabled { get; set; }
    [DataMember]
    public string Description { get; set; }
}

I read the above XML data from a server like this:

WebRequest client = WebRequest.Create( "http://server:80/datasources" );
using( StreamReader sr = new StreamReader( client.GetResponse().GetResponseStream()) ) {
    string xml = sr.ReadToEnd();
var response = ServiceStack.Text.XmlSerializer.DeserializeFromString<ArrayOfRESTDataSource>( xml );
}

My question is: What do I need to change or decorate public RESTDataSource[] Data with to get the deseralization to work for the array? Serializing single RESTDataSource items work just fine, its just the array I can't get to work.

Thanks in advance.

Update 1

As @mythz suggested, I updated my code to this, but response.Data is still null. What did I not understand?

[DataContract( Namespace = "http://SwitchKing.Common/Entities/RESTSimplified/2010/07" )]
 public class ArrayOfRESTDataSource
{
    [DataMember]
    public DataSource Data { set; get; }
}

[CollectionDataContract( ItemName = "RESTDataSource" )]
public class DataSource : List<RESTDataSource>
{
    public DataSource() { }
    public DataSource( IEnumerable<RESTDataSource> collection ) : base( collection ) { }
}

Update 2

The solution is in @mythz answer below, but just for completeness/clarity: What I did wrong was to add another level in my DTOs - the top-level class ArrayOfRESTDataSource is the one that actually has the sub items in XML so it is that one that should be of a collection type.

4

1 に答える 1

8

[CollectionDataContract(...)]配列/コレクションのシリアル化出力を変更するために使用できます。例については、この前の回答を参照してください。

シリアル化と統合の問題のデバッグ

このような統合の問題を解決しようとするときの最初のステップは、問題を切り分けることです。つまり、他のすべてを削除して、問題に集中します。たとえば、この場合、XMLとDTOに焦点を当て、それらをサービスから切り離します。

ServiceStackは、内部で.NETのXml DataContractSerializerを使用するだけで、余分な変換やバイトオーバーヘッド(そのままシリアル化された生のDTO)を追加しないため、サービスの外部で機能させることができれば、同じDTOを配置できます。サービスに戻ると、ネットワーク上でも機能します。

便利なServiceStack拡張メソッド

ServiceStackは、データモデルをシリアル化/逆シリアル化および分析するための便利な拡張メソッドを提供します。

シリアル化/非シリアル化拡張メソッド

T.ToJson() / string.FromJson<T>()  //Serialize JSON
T.ToJsv() / string.FromJsv<T>()    //Serialize JSV  
T.ToXml() / string.FromXml<T>()    //Serialize XML

ハンディダンプユーティリティ

オブジェクトグラフをPrettyJSVDumpFormatで再帰的に印刷します

T.PrintDump()      

string.Format() args(存在する場合)を解決する文字列をコンソールに出力します

string.Print(args)    

シリアル化されたDTOはどのように見えますか

DTOの形状を考え出すときに行う必要がある最初のステップは、DTOにデータを入力して印刷し、それがどのように見えるかを確認することです。XML出力のチャンクを見て、私はこれらのDTOを思いつきました。

[DataContract(Namespace = "http://SwitchKing.Common/Entities/RESTSimplified/2010/07")]
public class RESTDataSource
{
    [DataMember]
    public bool Enabled { get; set; }
    [DataMember]
    public string Description { get; set; }
}

[CollectionDataContract(ItemName = "RESTDataSource", Namespace = "http://SwitchKing.Common/Entities/RESTSimplified/2010/07")]
public class ArrayOfRESTDataSource : List<RESTDataSource>
{
    public ArrayOfRESTDataSource() { }
    public ArrayOfRESTDataSource(IEnumerable<RESTDataSource> collection) : base(collection) { }
}

次に、それらを入力してダンプします。

var dto = new ArrayOfRESTDataSource { 
    new RESTDataSource { Enabled = true, Description = "MyTest" } };

dto.ToXml().Print();

コンソールに出力するもの:

<?xml version="1.0" encoding="utf-8"?><ArrayOfRESTDataSource xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://SwitchKing.Common/Entities/RESTSimplified/2010/07"><RESTDataSource><Description>MyTest</Description><Enabled>true</Enabled></RESTDataSource></ArrayOfRESTDataSource>

これは私たちが望むもののように見えます。期待されるXMLと同じチャンクを取得するまで、上記のDTOを微調整しない場合。

XMLと同じ形のDTOがある場合は、それらのシリアル化を試みることができます。

var dto = xml.FromXml<ArrayOfRESTDataSource>();
dto.PrintDump();

これは、このきれいなオブジェクトグラフを印刷します:

[
    {
        Enabled: True,
        Description: MyTest
    }
]

すべてのフィールドに期待値が入力されている場合は、これで完了です。ServiceStackWebサービスのDTOを更新できます。

于 2012-11-18T20:50:15.603 に答える