Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor in WCF DataContract not reflected on Client

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();

        }
    }
}
like image 788
Subhasis Avatar asked Jun 11 '11 13:06

Subhasis


People also ask

Is Datacontract mandatory in WCF?

No, the DataContractAttribute is not required - WCF will infer serialization rules.

What is Datacontract in WCF?

A data contract is a formal agreement between a service and a client that abstractly describes the data to be exchanged. That is, to communicate, the client and the service do not have to share the same types, only the same data contracts.

Why Datacontract is used in WCF?

Data Contract defines the structure of data, using which the client and service will exchange data. The WCF runtime uses a method called the Serializer to serialize and de-serialize the data on the network. Data converted into an XML format before sharing on the network is serialization.

Why use DataContract?

It is used to get or set the order of serialization and deserialization of a member. It instructs the serialization engine that member must be present while reading or deserializing. It gets or sets the DataMember name. It will specify whether the default value to be serialized.


2 Answers

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.

like image 158
Sam Holder Avatar answered Oct 05 '22 15:10

Sam Holder


make Proxy class in your client side:

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

and use your proxy class, not generated client class:

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

        }
    }
}
like image 33
godot Avatar answered Oct 05 '22 15:10

godot