WCF задыхается от свойств без «набора». Есть обходной путь?


97

У меня есть класс, который я передаю в результате метода службы, и у этого класса есть свойство только для получения:

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

Я получаю исключение на стороне сервиса:

System.Runtime.Serialization.InvalidDataContractException: не установлен метод для свойства «Сообщение» в типе «MyNamespace.ErrorBase».

У меня должно быть это свойство только как получатель, я не могу разрешить пользователям присваивать ему значение. Какое решение я мог бы использовать? Или мне не хватает какого-то дополнительного атрибута?

Ответы:


107

Дайте Message общедоступный получатель, но защищенный установщик, чтобы только подклассы (и DataContractSerializer, потому что он читер :) могли изменять значение.


Отличное решение!
Рассел

Спасибо, рад, что это было полезно! На самом деле это лишь одно из нескольких применений этого трюка. Поскольку методы получения и установки являются технически функциями, вы также можете использовать тот же метод для обеспечения настраиваемой сериализации примитивных типов (возможно, настраиваемого формата времени в XML) без необходимости использования устрашающего IDataContractSurrogate.
рх.

28
Вы даже можете сделать это приватным. Сериализатору не важно, является ли он частным, общедоступным, защищенным, внутренним или защищенным внутренним.
Авель

8
и сделайте сеттерthrow new NotSupportedException()
Simon_Weaver

2
Имея private set;работает , если вы используете [DataContract]и [DataMember]. Если вы их опустите, вам понадобится public set;.
user276648

12

Даже если вам не нужно обновлять значение, установщик используется WCFSerializer для десериализации объекта (и повторной установки значения).

Это то, что вам нужно: WCF DataContracts


1
Значит, единственный способ решить эту проблему - сделать это методом, а не свойством? Опять же, я не могу позволить "установить" на это свойство
Андрей

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

1
Этот вопрос о stackoverflow попадает в самую точку
Рассел,


5

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


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

4

Не могли бы вы просто установить "ничего не делать" ??

[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.