WCF s'étouffe sur les propriétés sans «ensemble». Une solution de contournement?

97

J'ai une classe que je passe à la suite d'une méthode de service, et cette classe a une propriété get-only:

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

Je reçois une exception côté service:

System.Runtime.Serialization.InvalidDataContractException: Aucune méthode définie pour la propriété «Message» de type «MyNamespace.ErrorBase».

Je dois avoir cette propriété comme seul getter, je ne peux pas permettre aux utilisateurs de lui attribuer une valeur. Une solution de contournement que je pourrais utiliser? Ou est-ce que je manque un attribut supplémentaire?

Andreï
la source

Réponses:

106

Donnez à Message un getter public mais un setter protégé, afin que seules les sous-classes (et le DataContractSerializer, car il triche :) puissent modifier la valeur.

rh.
la source
C'est une bonne solution!
Russell
Merci, content que cela ait été utile! Ce n'est en fait qu'une des nombreuses utilisations de cette astuce. Étant donné que les getters et les setters sont techniquement des fonctions, vous pouvez également utiliser cette même technique pour fournir une sérialisation personnalisée des types primitifs (peut-être un format d'heure personnalisé en XML) sans avoir à utiliser l'intimidant IDataContractSurrogate.
rh.
28
Vous pouvez même le rendre privé. Le sérialiseur ne se soucie pas de savoir s'il est privé, public, protégé, interne ou protégé interne.
Abel
8
et faire le setterthrow new NotSupportedException()
Simon_Weaver
2
Avoir un private set;fonctionne si vous utilisez [DataContract]et [DataMember]. Si vous les omettez, vous en avez besoin public set;.
user276648
12

Même si vous n'avez pas besoin de mettre à jour la valeur, le setter est utilisé par le WCFSerializer pour désérialiser l'objet (et redéfinir la valeur).

Ce SO est ce que vous recherchez: WCF DataContracts

Russell
la source
1
Donc, la seule façon pour moi de surmonter le problème est d'en faire une méthode plutôt qu'une propriété? Encore une fois, je ne peux pas autoriser "set" sur cette propriété
Andrey
Vous pouvez en faire une méthode (par exemple, GetMessage () {return "";}) alternativement, je suis presque sûr que vous pourriez dire au sérialiseur WCF de l'ignorer. Je vais voir ce que je peux trouver et vous le faire savoir.,
Russell
1
Cette question de stackoverflow touche le clou sur la tête: stackoverflow.com/questions/172681/wcf-datacontracts
Russell
11
[DataMember(Name = "PropertyName")]
public string PropertyName
{
    get
    {
        return "";
    }
    private set
    { }
}
Rikin Patel
la source
5

Si vous n'avez qu'un getter, pourquoi avez-vous besoin de sérialiser la propriété? Il semble que vous puissiez supprimer l'attribut DataMember pour la propriété en lecture seule, et le sérialiseur ignorerait simplement la propriété.

Rob Lambert
la source
3
Cela n'a en effet pas de sens de sérialiser une propriété dérivée (par exemple, une propriété d'URL qui est calculée à partir d'une propriété d'ID) vers un stockage persistant (par exemple, une base de données) - vote favorable pour cela - mais il est logique de la sérialiser en un représentation (par exemple, JSON ou XML) qui est renvoyée par une requête API.
Florian Winter
3

Ne pourriez-vous pas avoir un setter "ne rien faire" ??

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

Ou est-ce que le sérialiseur DataContract barf à cela, aussi ??

marc_s
la source
14
Cela ne fait rien, je ne voulais tout simplement pas laisser les développeurs utilisant l'API client penser qu'ils peuvent attribuer des éléments à la propriété.
Andrey
2

Les propriétés avec l'attribut DataMember doivent toujours être définies. Vous devez réécrire un objet simmilar sur l'application client car les membres DataContract peuvent toujours se voir attribuer des valeurs.

Jojo Sardez
la source
2

J'ai eu ce problème avec ASP.NET MVC et moi voulant utiliser DataContractSerializer afin de pouvoir contrôler les noms sur les éléments dans la sortie JSON. Finalement, j'ai basculé le sérialiseur vers JSON.NET, qui prend en charge les propriétés sans setters (ce que DataContractSerializer ne fait pas) et le contrôle de nom de propriété (ce que le sérialiseur JSON intégré dans ASP.NET MVC ne fait pas) via [JsonProperty(PropertyName = "myName")].

Thomas Lundström
la source
2

Si c'est une option viable, au lieu d'avoir ErrorBasecomme classe de base, définissez-la comme suit:

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

            // leave unattributed
            set;
        }
    }

Maintenant, même si un setter existe, il est inaccessible au client via le canal WCF, c'est donc comme s'il était privé.

Gilad
la source