从XML数据反序列化数组(在ServiceStack中)

Per*_*Per 5 c# xml-serialization servicestack

我有以下大量的XML数据:

<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>
Run Code Online (Sandbox Code Playgroud)

RESTDataSource 可以发生0-n次.

这是我的课程:

[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; }
}
Run Code Online (Sandbox Code Playgroud)

我从这样的服务器上读取了上面的XML数据:

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 );
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:我需要更改或装饰什么public RESTDataSource[] Data才能让deseralization适用于阵列?序列化单个RESTDataSource项工作得很好,它只是我无法工作的数组.

提前致谢.

更新1

正如@mythz建议的那样,我将代码更新为此,但response.Data仍然为null.我什么不明白?

[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 ) { }
}
Run Code Online (Sandbox Code Playgroud)

更新2

解决方案在下面的@mythz答案中,但仅仅是为了完整性/清晰度:我做错了是在我的DTO中添加另一个级别 - 顶级类ArrayOfRESTDataSource是实际拥有XML中的子项的那个,所以它就是那个应该是一个集合类型.

myt*_*thz 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
Run Code Online (Sandbox Code Playgroud)

方便的转储实用程序

Pretty JSV转储格式递归打印对象图

T.PrintDump()      
Run Code Online (Sandbox Code Playgroud)

将字符串打印到控制台解析string.Format() args(如果有)

string.Print(args)    
Run Code Online (Sandbox Code Playgroud)

您的序列化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) { }
}
Run Code Online (Sandbox Code Playgroud)

然后填充并转储它们:

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

dto.ToXml().Print();
Run Code Online (Sandbox Code Playgroud)

哪些打印到控制台:

<?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>
Run Code Online (Sandbox Code Playgroud)

这看起来像我们想要的.如果它没有调整上面的DTO,直到你获得与预期的XML相同的块.

当您具有与XML相同形状的DTO时,您可以开始尝试序列化它们:

var dto = xml.FromXml<ArrayOfRESTDataSource>();
dto.PrintDump();
Run Code Online (Sandbox Code Playgroud)

这将打印这个漂亮的对象图:

[
    {
        Enabled: True,
        Description: MyTest
    }
]
Run Code Online (Sandbox Code Playgroud)

如果所有字段都填充了预期值,那么您就完成了,并且可以更新ServiceStack Web服务DTO.