WCF: предоставление свойств DataMember только для чтения без набора?
у меня есть класс на стороне сервера, который я делаю доступным на стороне клиента через [DataContract]. Этот класс имеет поле readonly, которое я хотел бы сделать доступным через свойство. Однако я не могу этого сделать, потому что не похоже, что мне разрешено добавлять свойство [DataMember] без наличия get и set.
Итак - есть ли способ иметь свойство [DataMember] без сеттера?
[DataContract]
class SomeClass
{
private readonly int _id;
public SomeClass() { .. }
[DataMember]
public int Id { get { return _id; } }
[DataMember]
public string SomeString { get; set; }
}
или решение будет использовать [DataMember] в качестве поля - (например, показано здесь)? Пробовал делать это тоже, но, похоже, ему все равно, что поле только для чтения..?
редактировать: единственный способ сделать свойство readonly, взломав его так? (нет - я не хочу этого делать...)
[DataMember]
public int Id
{
get { return _id; }
private set { /* NOOP */ }
}
5 ответов
ваш класс " на стороне сервера "не будет" доступен " клиенту, на самом деле.
происходит следующее: на основе контракта данных клиент создаст новый отдельный класс из XML-схемы службы. Это не может используйте серверный класс как таковой!
он повторно создаст новый класс из определения схемы XML, но эта схема не содержит каких-либо специфических вещей .NET, таких как видимость или модификаторы доступа - это просто схема XML, в конце концов. Класс на стороне клиента будет создан таким образом, чтобы он имел тот же "след" на проводе - например, он сериализуется в тот же формат XML, в основном.
вы не может "транспорт" .NET конкретные ноу-хау о классе через стандартную службу на основе SOAP - в конце концов, все, что вы проходите вокруг сериализованного сообщения - никаких классов!
установите флажок "четыре принципа SOA" (определяется Don Box of Microsoft):
- границы четкие
- услуги автономной
- службы разделяют схему и контракт, а не класс
- совместимость основана на политике
см. пункт #3-Схема и контракт совместного использования служб,не class - вы только когда - либо разделяете интерфейс и XML - схему для контракта данных-это все-нет классов .NET.
поместите атрибут DataMember в поле, не являющееся свойством.
помните мысль, что WCF не знает инкапсуляции. Инкапсуляция-это термин ООП, а не SOA.
тем не менее, помните, что поле будет читаться только для людей, использующих ваш класс - любой, кто использует сервис, будет иметь полный доступ к полю на своей стороне.
у меня были некоторые свойства в классе в моем слое обслуживания, который я хотел передать Silverlight. Я не хотел создавать новый класс.
не "рекомендуем", но это казалось меньшим из двух зол, чтобы пройти через Total
свойство silverlight (исключительно для визуальной привязки данных).
public class PricingSummary
{
public int TotalItemCount { get; set; } // doesnt ideally belong here but used by top bar when out of store area
public decimal SubTotal { get; set; }
public decimal? Taxes { get; set; }
public decimal Discount { get; set; }
public decimal? ShippingTotal { get; set; }
public decimal Total
{
get
{
return + SubTotal
+ (ShippingTotal ?? 0)
+ (Taxes ?? 0)
- Discount;
}
set
{
throw new ApplicationException("Cannot be set");
}
}
}
есть способ достичь этого. Но имейте в виду, что это напрямую нарушает следующий принцип, приведенный в ответ:
"3. Службы совместно используют схему и контракт, а не класс."
если это нарушение не касается, вот что:
-
переместите контракты на обслуживание и данные в отдельную (портативную) библиотеку классов. (Назовем это собрание
SomeService.Contracts
.) Вот как бы вы определили неизменный[DataContract]
класс:namespace SomeService.Contracts { [DataContract] public sealed class Foo { public Foo(int x) { this.x = x; } public int X { get { return x; } } [DataMember] // NB: applied to the backing field, not to the property! private readonly int x; } }
отметим, что
[DataMember]
применяется к вспомогательному полю, и не к соответствующему свойству только для чтения. -
ссылка на сборку контракта из вашего проекта приложения-службы (я буду называть мой
SomeService.Web
) и из ваших клиентских проектов (Мой называетсяSomeService.Client
). Это может привести к следующим зависимостям проекта внутри вашего решение: -
далее при добавлении ссылки на службу в клиентский проект убедитесь, что включена опция "типы повторного использования", и убедитесь, что сборка контракта (
SomeService.Contracts
) будет включен в этот:
вуаля! Visual Studio вместо создания нового Foo
введите из схемы WSDL службы, будет повторно использовать неизменяемый Foo
введите из вашего контракта собрание.
последнее предупреждение: вы уже отклонились от принципов обслуживания, приведенных в этот другой ответ. Но постарайся больше не сбиваться с пути. У вас может возникнуть соблазн начать добавлять (бизнес) логику в классы контрактов данных; не делайте этого. Они должны оставаться как можно ближе к немым объектам передачи данных (DTOs), как вы можете управлять.
определите контракт на обслуживание (интерфейс) перед реализацией контракта с использованием класса.