我可以将DataMember添加到WCF中的CollectionDataContract吗?

时间:2009-01-23 00:01:25

标签: .net wcf

我有一个我用CollectionDataContract修饰的集合类。集合类还在类上有一个属性,我希望将其传递给服务客户端。我已经尝试将[DataMember]添加到该属性,但是在我更新时它没有将它添加到客户端的类中。

那里的任何WCF专家都有任何帮助吗?

3 个答案:

答案 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>

为了我的目的,这完美无缺。它根据需要进行序列化和反序列化。