Атрибут WCF DataMember для полей только для чтения?

Я пытаюсь создать класс с полем Id, доступным только для чтения, однако у меня возникают проблемы с сохранением значения, когда объект проходит через сервер WCF.

Я не могу установить атрибут [DataMember] в общедоступном свойстве, поскольку не существует метода set, и я хотел бы сохранить его таким образом, если это возможно, поскольку я не хочу, чтобы это значение изменялось внешними средствами. Я не могу установить атрибут [DataMember] в частном поле, так как он вызывает ошибку в средах с частичным доверием.

public class MyClass
{
    private int _id;

    public int Id 
    { 
        get { return _id; } 
    }

    private string _otherProperties;

    [DataMember]
    public string OtherProperties
    {
        get { return _otherProperties; } 
        set { _otherProperties = value; }
    }
}

Есть ли способ сохранить значение поля Id при прохождении через сервер WCF, не делая мое свойство общедоступным?


person Rachel    schedule 29.09.2010    source источник
comment
msdn.microsoft.com/en-us/library/ms733127.aspx: Он не должен вызывать ошибку, если у вас есть частный метод. В примечании вы можете видеть: DataContract не заботится о видимости метода.   -  person Patrick Desjardins    schedule 20.07.2011


Ответы (3)


Вообще говоря, ваши классы контрактов данных должны быть очень легкими объектами передачи данных без какой-либо логики или более глубокого смысла, придаваемого им. Просто контейнеры для передачи данных через облако. Это должны быть общедоступные классы с набором общедоступных свойств для чтения и записи. В классах бизнес-логики вы должны преобразовать их во внутренние бизнес-объекты и сделать обратное при передаче данных.

Это отделяет модель передачи данных от любой внутренней модели сущности и обеспечивает оптимальную ремонтопригодность, позволяя избежать таких проблем, как та, с которой вы столкнулись, когда проблемы объектно-ориентированного проектирования конфликтуют с рабочим поведением WCF.

В очень маленьких проектах затраты на ведение отдельной модели могут не окупиться. AutoMapper может помочь минимизировать необходимость ручного труда.

Говоря о вашем конкретном сценарии, я не уверен, что точно понимаю постановку проблемы. Вы не хотите, чтобы какое-то поле было изменено? Но это поле - всего лишь часть модели данных - части модели данных никогда не «модифицируются» - нет «старых» данных, только данные, которые создает ваш клиент. Ваш клиентский код просто отправляет объект данных на сервер. Если сервер не заботится об одном члене класса, он должен просто игнорировать его.

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

person Sander    schedule 29.09.2010
comment
Позвольте мне посмотреть, правильно ли я понимаю ... вы предлагаете, чтобы каждый объект состоял из двух частей: класса DataTransfer (DataContract) для отправки / получения данных на / с сервера WCF и самого фактического класса, который содержит бизнес-логику, INotifyPropertyChanged, функциональность и т. Д.? - person Rachel; 29.09.2010
comment
И да и нет. Объекты передачи данных не должны фактически однозначно отображать какие-либо объекты бизнес-логики. Например, у меня может быть большой и сложный бизнес-объект Employee, но при выполнении различных операций WCF я просто предоставляю данные, относящиеся к конкретной операции. Например. UpdateContactInfo (Guid employeeID, ContactInfo info) будет содержать только контактную информацию, хотя она может по-прежнему быть частью моего бизнес-объекта Employee. Однако для небольших сценариев объект передачи данных и бизнес-объект, как правило, почти идентичны - только без каких-либо нежелательных полей (например, хеша пароля). - person Sander; 05.10.2010

Ты можешь это сделать:

public int Id
{
     get;
     private set;
}

Это сделает десериализатор счастливым, не позволяя при этом устанавливать значение идентификатора. Вам нужно будет установить его в конструкторе или в установщике другого свойства.

Однако я согласен с Сандерсом в том, что ваш DTO должен быть тупым контейнером.

person FlySwat    schedule 29.09.2010

Нет. Для сериализации член данных должен иметь геттер и сеттер. Проверка того, что Id не был изменен на клиенте, является обязанностью службы.

person Ladislav Mrnka    schedule 29.09.2010