ВКФ:Открытие свойств DataMember только для чтения без установки?

StackOverflow https://stackoverflow.com/questions/1873741

Вопрос

У меня есть класс на стороне сервера, который я делаю доступным на стороне клиента через [DataContract].В этом классе есть поле только для чтения, которое я хотел бы сделать доступным через свойство.Однако я не могу этого сделать, потому что мне не разрешено добавлять свойство [DataMember] без получения и установки.

Итак, есть ли способ иметь свойство [DataMember] без установщика?

[DataContract]
class SomeClass
{
    private readonly int _id; 

    public SomeClass() { .. }

    [DataMember]
    public int Id { get { return _id; } }        

    [DataMember]
    public string SomeString { get; set; }
}

Или решение будет использовать [DataMember] в качестве поля (например,показано здесь)?Пробовал сделать это тоже, но, похоже, его не волнует, что поле доступно только для чтения..?

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

[DataMember]
public int Id
{
    get { return _id; }
    private set { /* NOOP */ }
}
Это было полезно?

Решение

На самом деле ваш «серверный» класс не будет «доступен» клиенту.

Происходит следующее:На основе контракта данных клиент создаст новый отдельный класс из XML-схемы сервиса.Это не могу используйте серверный класс как таковой!

Он заново создаст новый класс из определения схемы XML, но эта схема не содержит никаких специфических вещей .NET, таких как модификаторы видимости или доступа — в конце концов, это всего лишь схема XML.Класс на стороне клиента будет создан таким образом, чтобы он имел один и тот же «след» в сети, напримерпо сути, он сериализуется в тот же формат XML.

Ты не могу «переносить» специфичные для .NET ноу-хау о классе через стандартную службу на основе SOAP — в конце концов, все, что вы передаете, — это сериализованные сообщения - никаких занятий!

Проверьте «Четыре принципа SOA» (определенные Доном Боксом из Microsoft):

  1. Границы четкие
  2. Сервисы автономны
  3. Службы совместно используют схему и контракт, а не класс
  4. Совместимость основана на политике

См. пункт № 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.Службы совместно используют схему и контракт, а не класс».

Если данное нарушение вас не касается, то делайте следующее:

  1. Переместите контракты служб и данных в отдельную (переносимую) библиотеку классов.(Назовем эту сборку 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] применяется к фоновому полю, и нет в соответствующее свойство, доступное только для чтения.

  2. Ссылайтесь на сборку контракта из обоих проектов вашего сервисного приложения (я назову свой SomeService.Web) и из ваших клиентских проектов (мой называется SomeService.Client).Это может привести к появлению следующих зависимостей проекта внутри вашего решения:

    screenshot highlighting the project dependencies in Solution Explorer

  3. Затем, когда вы добавляете ссылку на службу в свой клиентский проект, убедитесь, что опция «повторное использование типов» включена, и убедитесь, что ваша сборка контракта (SomeService.Contracts) будет включено в это:

    screenshot highlighting the relevant service reference setting

Вуаля!Visual Studio вместо создания нового Foo из схемы WSDL службы, будет повторно использовать неизменяемый Foo типа из вашей контрактной сборки.

Последнее предупреждение:Вы уже отошли от принципов обслуживания, изложенных в тот другой ответ.Но постарайтесь не отклоняться дальше.У вас может возникнуть соблазн начать добавлять (бизнес) логику в классы контрактов данных;не.Они должны оставаться как можно ближе к объектам передачи данных (DTO).

Определите контракт службы (интерфейс). Прежде чем реализовывать контракт с помощью класса.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top