WCF DataContract со свойствами только для чтения

Я пытаюсь вернуть сложный тип из метода службы в WCF. Я использую C # и .NET 4. Этот сложный тип должен быть инвариантным (точно так же, как строки .net). Более того, служба только возвращает его и никогда не принимает в качестве аргумента.

Если я попытаюсь определить только геттеры для свойств, я получу ошибку времени выполнения. Я предполагаю, что это связано с тем, что никакие сеттеры не приводят к сбою сериализации. Тем не менее, я считаю, что этот тип должен быть инвариантным.

Пример:

[DataContract]
class A 
{
   [DataMember]
   int ReadOnlyProperty {get; private set;}
}

Служба не загружается из-за проблемы с сериализацией.

Есть ли способ сделать в контракте данных WCF свойства только для чтения? Возможно, заменив сериализатор? Если да, то как? Если нет, что вы посоветуете для решения этой проблемы?

Спасибо,
Асаф


person Asaf R    schedule 22.03.2010    source источник
comment
Возможно, вы сможете использовать поля только для чтения (не свойства) и инициализировать их в конструкции вашего класса. Также ..., возможный дубликат: stackoverflow.com/q/1873741/945456   -  person Jeff B    schedule 07.11.2015
comment
Это даже более важно сегодня с переходом к неизменяемым классам и поддержкой C # -6.0 автоматически реализуемых свойств только для получения.   -  person binki    schedule 02.04.2016


Ответы (8)


Поле DataMember не может быть доступно только для чтения, потому что wcf не сериализует объект как есть, и каждый раз перед началом десериализации создает новый экземпляр объекта, используя конструктор по умолчанию. Диспетчеры используют сеттеры для установки значений полей после десериализации.

Но весь верхний текст может быть большой ошибкой :)

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

person Stremlenye    schedule 24.03.2010
comment
Фактически он не вызывает конструктор по умолчанию во время десериализации. docs.microsoft. com / en-us / dotnet / api / - person XWIKO; 22.08.2018
comment
У него также нет проблем с настройкой частных членов. - person Mathias Becher; 06.02.2020

поставьте [DataMember] на поле поддержки, сеттер вам не понадобится.

person Krzysztof Kozmic    schedule 22.03.2010
comment
Но он не будет доступен только для чтения и не будет означать, что он должен быть доступен только для чтения. - person Asaf R; 22.03.2010
comment
он никогда не будет доступен только для чтения. Datacontract при передаче по сети - это просто XML. вы не можете сделать часть XML только для чтения. Вы не можете заставить того, кто находится на другом конце провода, не изменять его значение. Это просто так не работает. - person Krzysztof Kozmic; 22.03.2010
comment
Вы могли бы просто игнорировать значение, если оно передается в службу? Под словом "только чтение" вы имеете в виду, что служба только его возвращает? - person Bryan Denny; 22.03.2010
comment
@ Брайан: ага. Сервис только возвращает его, и я хочу выразить именно это. - person Asaf R; 23.03.2010

Сделайте свой сеттер общедоступным, чтобы удовлетворить сериализатор, но просто не делайте ничего в сеттере. Не пурист, но добивается цели

public string MyProperty 
{
    get {
        return this._myProperty
    }
    set {}
}
person Mike Emo    schedule 27.01.2014

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

[DataContract]
public class A 
{
   public class A(){}
   public class A(int readonlyproperty){ _readonlyproperty = readonlyproperty}

   [DataMember(Name = "ReadOnlyProperty")]
   internal int _readonlyproperty;

   public int ReadOnlyProperty {
      get {return _readonlyproperty;}
      private set {_readonlyproperty = value;}
}

Затем сделайте доступными ваши внутренние компоненты в wcf:

[assembly: InternalsVisibleTo("System.Runtime.Serialization")]

Некоторые примеры того, как использовать это в ваших интересах: wcf-and-datacontract-serialization-internals-and-tips

person Peter    schedule 02.10.2014

Как уже говорили другие, WCF нужны геттеры и сеттеры. При этом я пришел сюда с тем же вопросом, и ответы заставили меня спросить, зачем мне нужно свойство только для чтения. Если вы используете шаблон MVVM, класс, возвращаемый службой, является моделью, и поэтому пользовательский интерфейс не должен предоставлять его напрямую. Вы можете легко сделать ViewModel доступным только для чтения. В качестве альтернативы вы можете использовать класс фасада, не ориентированный на пользовательский интерфейс.

person DaveB    schedule 24.08.2014

Фактически, вы можете сделать поля, доступные только для чтения, сериализуемыми. Вам необходимо установить для свойства SerializeReadOnlyTypes DataContractSerializerSettings значение True при создании DataContractSerializer, как показано ниже:

var xmlSerializer = new DataContractSerializer(typeof(yourTypeHere),  new DataContractSerializerSettings {SerializeReadOnlyTypes=true});

См. Описание и подробности MSDN здесь: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializersettings(v=vs.110).aspx

person James    schedule 20.04.2015

WCF необходимо иметь возможность сериализовать / десериализовать свойство, что невозможно с частным свойством. Чтобы иметь свойство только для чтения (в сложном типе):

  • Оформить класс как [DataContract (IsReference = true)]
  • Украсьте каждое свойство как [DataMember]
  • Public Get, внутренний набор
    [DataContract(IsReference = true)]
    public class Format : ValueObject<Format>
    {
        [DataMember]
        public int Height { get; internal set; }
    }
person Thomas Hagström    schedule 30.04.2015

Вы пробовали сделать сеттер приватным?

Что-то типа:

public string MyProperty
{
get;
private set;
}
person Bryan Denny    schedule 22.03.2010
comment
Ага. Это как раз моя проблема. - person Asaf R; 22.03.2010
comment
Так это исправлено? Или это то, что вы пробовали? - person Bryan Denny; 22.03.2010
comment
Не работает. Если я сделаю MyProperty [DataMember], я получу ошибку времени выполнения, вызванную, насколько я понимаю, сериализацией. Это происходит, как только служба загружается - даже не во время клиентской операции. - person Asaf R; 23.03.2010
comment
@AsafR: Правильно, похоже, у вас должен быть get / set для всех полей, чтобы сериализация / десериализация работала. Я не думаю, что есть способ обойти это из всего, что я читал :( - person Bryan Denny; 23.03.2010
comment
Если вы хотите выразить свое заключение в своем ответе выше, я буду рад сделать его принятым ответом. - person Asaf R; 23.03.2010