我有一个我用CollectionDataContract修饰的集合类。集合类还在类上有一个属性,我希望将其传递给服务客户端。我已经尝试将[DataMember]添加到该属性,但是在我更新时它没有将它添加到客户端的类中。
那里的任何WCF专家都有任何帮助吗?
答案 0 :(得分:12)
我的博客上发布了一个有效的解决方案:
http://borismod.blogspot.com/2009/04/wcf-collectiondatacontract-and.html
UPD:谢谢,你的评论,杰夫。 以下是非泛型类的摘要。您可以在我的博客的新帖子中找到完整的通用解决方案: http://borismod.blogspot.com/2009/06/v2-wcf-collectiondatacontract-and.html
[DataContract(IsReference = true)]
public class EntityCollectionWorkaround : ICollection
{
#region Constructor
public EntityCollectionWorkaround()
{
Entities = new List();
}
#endregion
[DataMember]
public int AdditionalProperty { get; set; }
[DataMember]
public List Entities { get; set; }
#region ICollection Members
// Implement here members of ICollection by wrapping Entities methods
#endregion
#region IEnumerable Members
// Implement here members of IIEnumerable by wrapping Entities methods
#endregion
}
答案 1 :(得分:3)
您可能需要考虑为您的类实现自定义序列化。最简单的方法是实现IXmlSerializable
,输出自定义属性的值,然后使用DataContractSerializer
将集合中子项的实例序列化到输出中。
答案 2 :(得分:1)
这个答案是作为@BorisModylevsky给出的答案的附加内容。我能找到的每个解决方案建议使用IXmlSerializable
。但这是我的问题:我有一个像这样的分层父子结构
public class Project
{
//Several properties here...
public ItemCollection Items { get; private set; }
public Project()
{
Items = new ItemCollection();
}
}
public class ItemCollection : IList<ItemDetails>
{
private List<ItemDetails> _list = new List<ItemDetails>();
public Project Parent { get; private set; }
///dependency injection...
public ItemCollection(Project parent)
{
this.Parent = parent;
}
//Interface methods here working with _list...
//In the `Add(ItemDetails item)` method, I update incoming items with item.Parent = this.Parent.
}
public class ItemDetails
{
public Project Parent { get; set; }
//Several properties here, including some sub classes
///dependency injection...
public ItemDetails(Project parent)
{
this.Parent = parent;
}
}
为了使DataContractSerializer
工作,我必须添加一些私有构造函数和所需的属性:
[DataContract(IsReference=true)]
public class Project
{
[DataMember(Order=0)]
public ItemCollection Items { get; private set; }
//[DataMember(Order=##)]
//Several properties here, including some other sub classes
public Project()
{
Items = new ItemCollection();
}
}
[CollectionDataContract(IsReference=true)]
public class ItemCollection : IList<ItemDetails>
{
private List<ItemDetails> _list = new List<ItemDetails>();
[DataMember(Order=0)]
public Project Parent { get; private set; }
///dependency injection...
public ItemCollection(Project parent)
{
this.Parent = parent;
}
//Private constructor for use with DataContractSerializer
private ItemCollection() { }
//Interface methods here working with _list...
}
[DataContract(IsReference=true)]
public class ItemDetails
{
[DataMember(Order=0)]
public Project Parent { get; private set; }
//[DataMember(Order=##)]
//Several properties here, including some sub classes
///dependency injection...
public ItemDetails(Project parent)
{
this.Parent = parent;
}
//Private constructor for use with DataContractSerializer
private ItemDetails() { }
}
问题是为集合创建了XML,如下所示:
<Project>
<!--OTHER PROJECT PROPERTIES HERE-->
<Items z:Id="i11">
<ItemDetails z:Id="i12">
<Parent z:Ref="i1"/>
<!--OTHER PROPERTIES HERE-->
</ItemDetails>
<ItemDetails z:Id="i16">
<Parent z:Ref="i1"/>
<!--OTHER PROPERTIES HERE-->
</ItemDetails>
</Items>
</Project>
XML中的Parent
下没有Items
属性。我可以说,CollectionDataContract
不支持集合类中的任何其他属性。
在这种情况下,如果我像许多人建议的那样实现了IXmlSerializable
,那么我将被卡住在ItemDetails中手动序列化和反序列化大量的结构(为了简洁起见,我没有在这里展示)。在这种情况下,DataContractSerializer对我来说几乎一文不值。
但是上面的@BorisModylevsky回答,我将代码更改为:
[DataContract(IsReference=true)]
public class Project
{
[DataMember(Order=0)]
public ItemCollection Items { get; private set; }
//[DataMember(Order=##)]
//Several properties here, including some other sub classes
public Project()
{
Items = new ItemCollection();
}
}
[DataContract(IsReference=true)]
public class ItemCollection : IList<ItemDetails>
{
//Refactored _list to ItemsList. I didn't have to; I could have used [DataMember(Name="ItemsList", Order=1)]
[DataMember(Order=1)]
private List<ItemDetails> ItemsList = new List<ItemDetails>();
[DataMember(Order=0)]
public Project Parent { get; private set; }
///dependency injection...
public ItemCollection(Project parent)
{
this.Parent = parent;
}
//Private constructor for use with DataContractSerializer
private ItemCollection() { }
//Interface methods here working with ItemsList...
}
[DataContract(IsReference=true)]
public class ItemDetails
{
[DataMember(Order=0)]
public Project Parent { get; private set; }
//[DataMember(Order=##)]
//Several properties here, including some sub classes
///dependency injection...
public ItemDetails(Project parent)
{
this.Parent = parent;
}
//Private constructor for use with DataContractSerializer
private ItemDetails() { }
}
总结一下:我将CollectionDataContract
更改为DataContract
并将DataMember
添加到我在集合中使用的私人列表中。这是有效的,因为DataContractSerializer
可以获取和设置私有属性/字段。现在XML看起来像这样:
<Project>
<!--OTHER PROJECT PROPERTIES HERE-->
<Items z:Id="i11">
<Parent z:Ref="i1"/>
<ItemsList>
<ItemDetails z:Id="i12">
<Parent z:Ref="i1"/>
<!--OTHER PROPERTIES HERE-->
</ItemDetails>
<ItemDetails z:Id="i16">
<Parent z:Ref="i1"/>
<!--OTHER PROPERTIES HERE-->
</ItemDetails>
</ItemsList>
</Items>
</Project>
为了我的目的,这完美无缺。它根据需要进行序列化和反序列化。