WCF drosselt Eigenschaften ohne „Set“. Irgendeine Problemumgehung?

97

Ich habe eine Klasse, die ich aufgrund einer Servicemethode übergebe, und diese Klasse hat eine get-only-Eigenschaft:

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

Ich bekomme eine Ausnahme auf der Serviceseite:

System.Runtime.Serialization.InvalidDataContractException: Keine festgelegte Methode für die Eigenschaft 'Message' vom Typ 'MyNamespace.ErrorBase'.

Ich muss diese Eigenschaft als einzigen Getter haben, ich kann Benutzern nicht erlauben, ihr einen Wert zuzuweisen. Gibt es eine Problemumgehung, die ich verwenden könnte? Oder fehlt mir ein zusätzliches Attribut?

Andrey
quelle

Antworten:

106

Geben Sie Message einen öffentlichen Getter, aber einen geschützten Setter, damit nur Unterklassen (und der DataContractSerializer, weil er betrügt :) den Wert ändern können.

rh.
quelle
Das ist eine gute Lösung!
Russell
Danke, ich bin froh, dass es nützlich war! Dies ist nur eine von mehreren Verwendungsmöglichkeiten für diesen Trick. Da Getter und Setter technisch gesehen Funktionen sind, können Sie dieselbe Technik auch verwenden, um eine benutzerdefinierte Serialisierung primitiver Typen (möglicherweise ein benutzerdefiniertes Zeitformat in XML) bereitzustellen, ohne das einschüchternde IDataContractSurrogate verwenden zu müssen.
rh.
28
Sie könnten es sogar privat machen. Dem Serializer ist es egal, ob er privat, öffentlich, geschützt, intern oder intern geschützt ist.
Abel
8
und machen Sie den Setterthrow new NotSupportedException()
Simon_Weaver
2
Ein private set;Werk haben, wenn Sie [DataContract]und verwenden [DataMember]. Wenn Sie sie weglassen, brauchen Sie public set;.
user276648
12

Auch wenn Sie den Wert nicht aktualisieren müssen, wird der Setter vom WCFSerializer verwendet, um das Objekt zu deserialisieren (und den Wert zurückzusetzen).

Diese SO ist genau das, wonach Sie suchen : WCF DataContracts

Russell
quelle
1
Der einzige Weg für mich, das Problem zu überwinden, besteht darin, es zu einer Methode anstelle von Eigentum zu machen. Auch hier kann ich nicht zulassen, dass diese Eigenschaft "gesetzt" wird
Andrey
Sie könnten es alternativ zu einer Methode machen (z. B. GetMessage () {return "";}). Ich bin mir ziemlich sicher, dass Sie dem WCF Serializer anweisen könnten, es zu ignorieren. Ich werde sehen, was ich finden kann und Sie wissen lassen.,
Russell
1
Diese Stackoverflow-Frage trifft den Nagel auf den Kopf: stackoverflow.com/questions/172681/wcf-datacontracts
Russell
11
[DataMember(Name = "PropertyName")]
public string PropertyName
{
    get
    {
        return "";
    }
    private set
    { }
}
Rikin Patel
quelle
5

Wenn Sie nur einen Getter haben, warum müssen Sie die Eigenschaft überhaupt serialisieren? Es scheint, als könnten Sie das DataMember-Attribut für die schreibgeschützte Eigenschaft entfernen, und der Serializer würde die Eigenschaft einfach ignorieren.

Rob Lambert
quelle
3
Es ist in der Tat nicht sinnvoll, eine abgeleitete Eigenschaft (z. B. eine URL-Eigenschaft, die aus einer ID-Eigenschaft berechnet wird) in einen dauerhaften Speicher (z. B. eine Datenbank) zu serialisieren - stimmen Sie dafür ab -, aber es ist sinnvoll, sie in eine zu serialisieren Darstellung (z. B. JSON oder XML), die von einer API-Anforderung zurückgegeben wird.
Florian Winter
3

Könnten Sie nicht einfach einen "Do-Nothing" -Setter haben?

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

Oder ist der DataContract-Serializer auch dabei?

marc_s
quelle
14
Es ist nicht barf, ich wollte nur nicht zulassen, dass die Entwickler, die die Client-API verwenden, glauben, dass sie der Eigenschaft etwas zuweisen können.
Andrey
2

Eigenschaften mit DataMember-Attribut müssen immer festgelegt werden. Sie sollten ein ähnliches Objekt erneut in die Clientanwendung schreiben, da DataContract-Mitgliedern immer Werte zugewiesen werden können.

Jojo Sardez
quelle
2

Ich hatte dieses Problem mit ASP.NET MVC und wollte DataContractSerializer verwenden, um die Namen der Elemente in der JSON-Ausgabe steuern zu können. Schließlich habe ich den Serializer über JSON.NET umgestellt, das Eigenschaften ohne Setter (was DataContractSerializer nicht unterstützt) und Eigenschaftsnamensteuerung (was der in JSP.NET MVC integrierte JSON-Serializer nicht unterstützt) unterstützt [JsonProperty(PropertyName = "myName")].

Thomas Lundström
quelle
2

Wenn dies eine praktikable Option ist ErrorBase, definieren Sie sie wie folgt , anstatt sie als Basisklasse zu verwenden:

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

            // leave unattributed
            set;
        }
    }

Obwohl ein Setter vorhanden ist, kann der Client über den WCF-Kanal nicht darauf zugreifen. Es ist also so, als wäre er privat.

Gilad
quelle