Могу ли я добавить DataMember в CollectionDataContract в WCF? - PullRequest
13 голосов
/ 23 января 2009

У меня есть класс коллекции, который я украсил с помощью CollectionDataContract. Класс коллекции также имеет свойство класса, которое я хотел бы передать клиенту службы. Я пытался добавить [DataMember] к этому свойству, но при обновлении он не добавлялся в класс в клиенте.

Любые эксперты WCF могут предложить какую-либо помощь?

Ответы [ 3 ]

12 голосов
/ 16 апреля 2009

Рабочее решение выложено в моем блоге:

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

    }

3 голосов
/ 23 января 2009

Возможно, вы захотите реализовать собственную сериализацию для вашего класса. Возможно, проще всего реализовать IXmlSerializable, вывести значения вашего пользовательского свойства и затем использовать DataContractSerializer для сериализации экземпляров дочерних элементов в коллекции для вывода.

1 голос
/ 12 марта 2015

Этот ответ предназначен в качестве дополнения к ответу @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>

Что для моих целей работает отлично. При необходимости сериализуется и десериализуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...