WCF задихається на властивості без “встановленого”. Будь-яке обхідне рішення?


97

У мене є клас, який я передаю в результаті методу служби, і цей клас має властивість get-only:

[DataContract]
public class ErrorBase
{
  [DataMember]
  public virtual string Message { get { return ""; } }
}

Я отримую виняток на стороні обслуговування:

System.Runtime.Serialization.InvalidDataContractException: Не встановлено метод для властивості 'Повідомлення' у типі 'MyNamespace.ErrorBase'.

Я повинен мати цю властивість лише як геттер, я не можу дозволити користувачам присвоювати йому значення. Будь-яке обхідне рішення, яке я міг би використати? Або мені не вистачає якогось додаткового атрибута?

Відповіді:


106

Дайте Повідомленню загальнодоступний, але захищений сетер, так що лише підкласи (і DataContractSerializer, оскільки він обманює :) можуть змінювати значення.


Це чудове рішення!
Рассел

Дякую, рада, що це було корисно! Це насправді лише одне з декількох застосувань цього фокусу. Оскільки геттери та сетери технічно є функціями, ви також можете використовувати цей самий прийом, щоб забезпечити користувацьку серіалізацію примітивних типів (можливо, власний формат часу в XML) без необхідності володіти залякуючим IDataContractSurrogate.
rh.

28
Ви навіть можете зробити це приватним. Серіалізатор не має значення, приватний, загальнодоступний, захищений, внутрішній чи захищений внутрішній.
Абель

8
і зробити сетераthrow new NotSupportedException()
Simon_Weaver

2
Маючи private set;твори, якщо ви використовуєте [DataContract]і [DataMember]. Якщо ви їх опустите, вам потрібно public set;.
user276648

12

Навіть якщо вам не потрібно оновлювати значення, установка використовується WCFSerializer для десеріалізації об'єкта (і повторного встановлення значення).

Це те, що ви шукаєте: WCF DataContracts


1
Тож єдиний спосіб для мене подолати проблему - зробити це методом, а не властивістю? Знову ж таки, я не можу дозволити "встановити" для цього майна
Андрій

Ви можете зробити це методом (наприклад, GetMessage () {return "";}), або ж я впевнений, що ви могли б сказати WCF Serializer ігнорувати його. Я подивлюсь, що зможу знайти, і повідомлю вас.,
Рассел

1
Це питання про stackoverflow потрапляє в цвях: stackoverflow.com/questions/172681/wcf-datacontracts
Рассел


5

Якщо у вас є лише геттер, навіщо взагалі вам потрібно серіалізувати майно. Здається, ви могли б видалити атрибут DataMember для властивості лише для читання, а серіалізатор просто ігнорував би властивість.


3
Дійсно, немає сенсу серіалізувати похідну властивість (наприклад, властивість URL-адреси, яка обчислюється з властивості ID) до постійного сховища (наприклад, бази даних) - голосуйте за це - але має сенс серіалізувати його до представлення (наприклад, JSON або XML), яке повертається запитом API.
Флоріан Зима

3

Чи не міг би ти просто мати сетера "нічого не робити" ??

[DataContract]
public class ErrorBase
{
  [DataMember]
  public virtual string Message 
  {
      get { return ""; } 
      set { }
  }
}

Або це також робить серіалізатор DataContract, також ??


14
Це не заважає, я просто не хотів, щоб розробники, що використовують клієнтський API, думали, що вони можуть призначити речі властивості.
Андрій

2

Властивості з атрибутом DataMember завжди вимагають встановлення. Вам слід повторно записати подібний об'єкт у клієнтській програмі, оскільки членам DataContract завжди можна присвоїти значення.


2

У мене була проблема з ASP.NET MVC, і я хотів використовувати DataContractSerializer для того, щоб мати можливість контролювати імена елементів у вихідному файлі JSON. Зрештою я переключив серіалізатор на JSON.NET, який підтримує властивості без сетерів (а DataContractSerializer - ні) та управління іменами властивостей (чого не вбудований серіалізатор JSON в ASP.NET MVC) через [JsonProperty(PropertyName = "myName")].


2

Якщо це життєздатний варіант, то замість того, щоб мати ErrorBaseбазовий клас, визначте його наступним чином:

    public interface IError
    {
        string Message
        {
            [OperationContract]
            get;

            // leave unattributed
            set;
        }
    }

Тепер, навіть якщо сеттер існує, він недоступний для клієнта через канал WCF, тож як би він був приватним.


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.