Constructor in WCF DataContract not reflected on Client

Subhasis picture Subhasis · Jun 11, 2011 · Viewed 17.3k times · Source

I need to have some data members get some values when I create an instance of the DataContract on the client. This is not happening using constructors. I have searched through different forums and found we have to use [OnDeserializing] and [OnDeserialized] attributes. This is also not working. Can somebody suggest something here. The other alternative is creating constructors in the partial classes at the client side. I want to avoid that.

Please find the code below:

Server-side: Datacontract

[DataContract]
public class Account
{

    private int mAccountId;
    private string mAccountName;

    public Account()
    {
        mAccountId = 5;
        mAccountName = "ABC";
    }

    [OnDeserializing]
    public void OnDeserializing(StreamingContext context)
    {
        mAccountId = 5;
        mAccountName = "ABC"; 
    }

    [OnDeserialized]
    public void OnDeserialized(StreamingContext context) 
    {

    } 

    [DataMember]
    public int AccountId
    {
        get
        {
            return mAccountId;
        }
        set
        {
            mAccountId = value;
        }
    }

    [DataMember]
    public string AccountName
    {
        get
        {
            return mAccountName;
        }
        set
        {
            mAccountName = value;
        }
    }


}

Client side - initialization

namespace TestClient
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Account acc = new Account();

        }
    }
}

Answer

Sam Holder picture Sam Holder · Jun 11, 2011

The properties attributed with the DataMember attributes only define what will be included in the generated WSDL/XSD. The client will generate its own classes based on the wsdl/xsd to use for communication with the service. It does not use the same classes which are used on the server.

This is why you will not get:

  • any constructors defined in the DataContract class
  • any private [DataMember] properties/fields (the client will always generate public properties/fields)
  • any behaviour defined in the DataContract class

Imagine the scenario where a java client wants to connect to your service. Do you expect the java classes to be generated with the same constructor? What about with the [OnDeserialized] attributes? What about a java script client, or python client?

When you start to think about it in this way you start to see why you cannot have what you want (at least not without sharing libraries between the client and server).

The reality is that you cannot force a client to have classes which always have default values and you cannot for a client to always send back valid data, the client can always just send a message which contains rubbish if it wants. You have a little control over some aspects of the message with the IsRequired and 'EmitDefaultValue` which will add checks into the xsd to ensure that something is present in the message, but you will have to do validation on the server, you can't assume that the objects you get back will be validated.

My suggestion would be to create DTOs from your domain objects to send across the wire, which contain no checking of any sort, they are just simple bags for holding the data. Then create factories to turn your domain objects into DTOs and DTOs into client objects. The factory simply takes the DTO and passes the members into the constructor of the domain object. Then your validation logic can live in the constructor of the domain object where it belongs. With the approach you currently have you will probably end up twisting the validation slightly so it can be done from both the constructor and in the [OnDeserialized] method.