103

I have some class that I'm passing as a result of a service method, and that class has a get-only property:

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

I'm getting an exception on service side:

System.Runtime.Serialization.InvalidDataContractException: No set method for property 'Message' in type 'MyNamespace.ErrorBase'.

I have to have this property as only getter, I can't allow users to assign it a value. Any workaround I could use? Or am I missing some additional attribute?

Mafii
  • 7,227
  • 1
  • 35
  • 55
Andrey
  • 20,487
  • 26
  • 108
  • 176
  • Don't mark a property that cannot be deserialized with `[DataMember]`. Adding the attribute will simply cause `DataContractSerializer` to throw an exception instead of checking if the property can be serialized or deserialized. – Suncat2000 May 10 '23 at 15:50

9 Answers9

112

Give Message a public getter but protected setter, so that only subclasses (and the DataContractSerializer, because it cheats :) may modify the value.

rh.
  • 1,731
  • 1
  • 10
  • 11
  • Thanks, glad it was useful! This actually is just one of several uses for this trick. Since getters and setters are technically functions, you can also use this same technique to provide custom serialization of primitive types (perhaps a custom time format in XML) without needing to wield the intimidating IDataContractSurrogate. – rh. Mar 01 '10 at 18:02
  • 29
    You could even make it private. The Serializer doesn't mind whether it's private, public, protected, internal or protected internal. – Abel May 07 '12 at 11:58
  • 8
    and make the setter `throw new NotSupportedException()` – Simon_Weaver Mar 15 '14 at 23:18
  • Dont' forget the [DataMember] attribute :) – Thomas Hagström Apr 30 '15 at 13:09
  • 3
    Having a `private set;` works if you use `[DataContract]` and `[DataMember]`. If you omit them, you need `public set;`. – user276648 Jul 19 '17 at 10:53
13

Even if you dont need to update the value, the setter is used by the WCFSerializer to deserialize the object (and re-set the value).

This SO is what you are after: WCF DataContracts

Community
  • 1
  • 1
Russell
  • 17,481
  • 23
  • 81
  • 125
  • 1
    So the only way for me to overcome the problem is to make it a method instead of property? Again, I can't allow "set" on this property – Andrey Feb 24 '10 at 02:33
  • You could make it a method (eg GetMessage() { return ""; }) alternatively, I am pretty sure you could tell the WCF Serializer to ignore it. I'll see what I can find and let you know., – Russell Feb 24 '10 at 02:34
  • 1
    This stackoverflow question hits the nail on the head: http://stackoverflow.com/questions/172681/wcf-datacontracts – Russell Feb 24 '10 at 02:36
12
[DataMember(Name = "PropertyName")]
public string PropertyName
{
    get
    {
        return "";
    }
    private set
    { }
}
Rikin Patel
  • 8,848
  • 7
  • 70
  • 78
7

If you only have a getter, why do you need to serialize the property at all. It seems like you could remove the DataMember attribute for the read-only property, and the serializer would just ignore the property.

Rob Lambert
  • 71
  • 1
  • 1
  • 4
    It does indeed not make sense to serialize a derived property (e.g., an URL property that is computed from an ID property) to a persistent storage (e.g., a database) - upvote for that - but it does make sense to serialize it to a representation (e.g., JSON or XML) that is returned by an API request. – Florian Winter May 12 '17 at 13:21
5

Couldn't you just have a "do-nothing" setter??

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

Or does the DataContract serializer barf at that, too??

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 14
    It doesn't barf, I just didn't want to let the developers using the client API think that they can assign stuff to the property. – Andrey Oct 14 '11 at 18:10
2

If it's a viable option, then instead of having ErrorBase as the base class, define it as follows:

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

            // leave unattributed
            set;
        }
    }

Now, even though a setter exists, it's inaccessible to the client via WCF channel, so it's as if it were private.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Gilad
  • 21
  • 1
2

Properties with DataMember attribute always requires set. You should re write simmilar object on the client application since DataContract members can always be assigned values.

Jojo Sardez
  • 8,400
  • 3
  • 27
  • 38
2

I had this problem with ASP.NET MVC and me wanting to use DataContractSerializer in order to be able to control the names on the items in the JSON output. Eventually I switched serializer to JSON.NET, which supports properties without setters (which DataContractSerializer doesn't) and property name control (which the built-in JSON serializer in ASP.NET MVC doesn't) via [JsonProperty(PropertyName = "myName")].

Thomas Lundström
  • 1,589
  • 1
  • 13
  • 18
1

If your serializer is of type DataContractJsonSerializer (or any DataContractSerializer) you can also use DataContractSerializerSettings in the constructor, with the SerializeReadOnlyTypes property set to true.

Aaron Thomas
  • 5,054
  • 8
  • 43
  • 89