Подтвердить что ты не робот

WCF: Показывать только свойства DataMember без набора?

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

Итак - есть ли способ иметь свойство [DataMember] без setter?

[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 */ }
}
4b9b3361

Ответ 1

Ваш "серверный" класс не будет "действительно доступен" клиенту.

Что происходит, так это: на основе контракта с данными клиент создаст новый отдельный класс из схемы XML службы. Он не может использовать серверный класс как таковой!

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

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

Проверьте "Четыре принципа SOA" (определенные Don Box от Microsoft):

  • Границы явны
  • Услуги автономны.
  • Схема общих служб и контракт, а не класс
  • Совместимость основана на политике

См. пункт № 3 - схема общего доступа к услугам и контракт, класс не - вы только делитесь интерфейсом и схемой XML для контракта с данными - все классы .NET.

Ответ 2

поместите атрибут DataMember в поле, а не в свойство.

Помните, что WCF не знает инкапсуляции. Инкапсуляция - это термин ООП, а не термин SOA.

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

Ответ 3

У меня были некоторые свойства в классе в моем сервисе, который я хотел передать 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");
        }
    }
}

Ответ 4

Есть способ достичь этого. Но следует предупредить, что это прямо нарушает следующий принцип, приведенный в этом ответе:

"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] применяется к полю резервного копирования, а не к соответствующему свойству только для чтения.

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

    screenshot highlighting the project dependencies in Solution Explorer

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

    screenshot highlighting the relevant service reference setting

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

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

Ответ 5

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