Конструктор в WCF DataContract не отражается на клиенте - PullRequest
9 голосов
/ 11 июня 2011

Мне нужно, чтобы некоторые члены данных получали некоторые значения при создании экземпляра DataContract на клиенте. Это не происходит с помощью конструкторов. Я искал на разных форумах и обнаружил, что мы должны использовать атрибуты [OnDeserializing] и [OnDeserialized]. Это тоже не работает. Может кто-нибудь предложить что-то здесь. Другой альтернативой является создание конструкторов в частичных классах на стороне клиента. Я хочу избежать этого.

Пожалуйста, найдите код ниже:

Серверная сторона: Datacontract

[DataContract]
public class Account
{

    private int mAccountId;
    private string mAccountName;

    public Account()
    {
        mAccountId = 5;
        mAccountName = "ABC";
    }

    [OnDeserializing]
    public void OnDeserializing(StreamingContext context)
    {
        mAccountId = 5;
        mAccountName = "ABC"; 
    }

    [OnDeserialized]
    public void OnDeserialized(StreamingContext context) 
    {

    } 

    [DataMember]
    public int AccountId
    {
        get
        {
            return mAccountId;
        }
        set
        {
            mAccountId = value;
        }
    }

    [DataMember]
    public string AccountName
    {
        get
        {
            return mAccountName;
        }
        set
        {
            mAccountName = value;
        }
    }


}

Клиентская сторона - инициализация

namespace TestClient
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Account acc = new Account();

        }
    }
}

Ответы [ 3 ]

15 голосов
/ 11 июня 2011

Генератор кода, используемый для создания прокси-классов WCF, создает совместимые типы контрактов и не использует тот же тип, который используется службой WCF. Самый простой способ добиться того, чего вы хотите, - это создать конструктор самостоятельно на своем клиенте, так как сгенерированный код: partial:

partial class Account
{
    public Account()
    {
        AcountId = 5;
        AccountName = "ABC";
    }
}

Если вы не хотите этого делать, вы можете заставить WCF повторно использовать типы, на которые уже ссылается ваш клиентский проект. Поэтому, если ваши классы контрактов данных находятся в отдельной библиотеке (как рекомендуется), вы можете сослаться на эту библиотеку и затем перенастроить свой клиентский проект WCF для повторного использования общих типов из указанной сборки.

14 голосов
/ 11 июня 2011

Свойства, связанные с атрибутами DataMember, определяют только то, что будет включено в сгенерированный WSDL / XSD.Клиент будет генерировать своих классов на основе wsdl / xsd для использования с сервисом.Он не использует те же классы, которые используются на сервере.

Вот почему вы не получите:

  • никаких конструкторов, определенных в DataContract class
  • любые частные [DataMember] свойства / поля (клиент всегда будет генерировать публичные свойства / поля)
  • любое поведение, определенное в DataContract class

Представьте себе сценарий, когда клиент Java хочет подключиться к вашему сервису.Ожидаете ли вы, что классы Java будут сгенерированы одним и тем же конструктором?А как насчет атрибутов [OnDeserialized]?Как насчет клиента сценариев Java или клиента Python?

Когда вы начинаете думать об этом таким образом, вы начинаете понимать, почему у вас не может быть того, чего вы хотите (по крайней мере, без совместного использования библиотек между клиентом и сервером).).

Реальность такова, что вы не можете заставить клиента иметь классы, которые всегда имеют значения по умолчанию, и вы не можете заставить клиента всегда отправлять обратно действительные данные, клиент всегда может просто отправить сообщение, содержащее мусор, еслиэто хочет.У вас есть небольшой контроль над некоторыми аспектами сообщения с помощью IsRequired и 'EmitDefaultValue`, которые добавят проверки в xsd, чтобы убедиться, что что-то присутствует в сообщении, но вам придется выполнить проверку на сервере, вы можетеНе думайте, что объекты, которые вы получите, будут проверены.

Я бы предложил создать DTO из ваших доменных объектов для отправки по проводам, которые не содержат никаких проверок, это всего лишь простые пакеты для хранения данных.Затем создайте фабрики, чтобы превратить ваши доменные объекты в DTO, а DTO в клиентские объекты.Фабрика просто принимает DTO и передает членов в конструктор объекта домена.Тогда ваша логика проверки может жить в конструкторе объекта домена, которому он принадлежит.С подходом, который у вас есть в настоящее время, вы, вероятно, в конечном итоге слегка повернете проверку, так что это можно сделать как из конструктора, так и из метода [OnDeserialized].

0 голосов
/ 04 мая 2018

создайте прокси-класс на вашей клиентской стороне :

public class AccountProxy: Account
{
   public AccountProxy()
   {
         mAccountId = 5;
         mAccountName = "ABC";
   }
}

и используйте свой прокси-класс, а не сгенерированный клиентский класс:

namespace TestClient
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            AccountProxy acc = new AccountProxy();

        }
    }
}
...