19
votes

I'm trying to return a complex type from a service method in WCF. I'm using C# and .NET 4. This complex type is meant to be invariant (the same way .net strings are). Furthermore, the service only returns it and never receives it as an argument.

If I try to define only getters on properties I get a run time error. I guess this is because no setters causes serialization to fail. Still, I think this type should be invariant.

Example:

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

The service fails to load due to a problem with serialization.

Is there a way to make readonly properties on a WCF DataContract? Perhaps by replacing the serializer? If so, how? If not, what would you suggest for this problem?

Thanks,
Asaf

8
You might be able to use readonly fields (not properties) and initialize them in the construct of your class. Also..., possible duplicate: stackoverflow.com/q/1873741/945456 - Jeff B
This is even more important today with the move to immutable classes and C#-6.0’s support for auto-implemented get-only properties. - binki

8 Answers

16
votes

put [DataMember] on backing field, you won't need a setter.

11
votes

Make your setter public to satisfy the serializer, but just don't do anything on the setter. Not 'purist' but gets it done

public string MyProperty 
{
    get {
        return this._myProperty
    }
    set {}
}
5
votes

DataMember Field can't be readonly, because wcf dont serialize object as-is and every time befor deserialization starts creates new object instance, using default constructor. Dispatchers use setters to set field values after deserialization.

But all upper text can be a big mistake :)

To make them realy readonly, make the server logic, validating thiss field values.

4
votes

You can't make the properties readonly, however you can get close to readonly by making the fields part of your contract instead of the properties:

[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;}
}

next make your internals accesable in wcf:

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

Some samples on how to use this to your advantage: wcf-and-datacontract-serialization-internals-and-tips

0
votes

Like others have said, WCF needs getters and setters. That being said, I came here with the same question and the answers made me ask why I needed a read-only property. If you use the MVVM pattern, the class returned by the service is the Model and so should not be exposed directly by the UI. You can easily make the ViewModel read-only. Alternatively you could use a non UI-targetted facade class.

0
votes

Actually, you can make the read-only fields serializable. You need to set the 'SerializeReadOnlyTypes' property of the DataContractSerializerSettings to 'True', when constructing the DataContractSerializer, as below:

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

See the MSDN description and details, here: https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializersettings(v=vs.110).aspx

0
votes

WCF needs to able to serialize / deserialize the property, which is not possible with a private property. To have a readonly property (within a complex type):

  • Decorate class as [DataContract(IsReference = true)]
  • Decorate each / the property as [DataMember]
  • Public Get, Internal Set
    [DataContract(IsReference = true)]
    public class Format : ValueObject<Format>
    {
        [DataMember]
        public int Height { get; internal set; }
    }
-1
votes

Have you tried making the setter private?

Something like:

public string MyProperty
{
get;
private set;
}