Serialization and Types
How does a DataContract type get initialized on the server? When I change the constructor for the type, nothing happens.
Older serializers relied on calling the parameter-less constructor to initialize the type when deserializing data. Data contract types have all of the data members initialized to the default values without a constructor being called. However, you can still introduce callback hooks into the serialization process by decorating methods on your data contract type with attributes. Here's a sample program that shows you exactly what goes on.
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Runtime.Serialization;
[DataContract]
public class Data
{
[DataMember]
public int a;
[OnDeserialized]
void OnDeserialized(StreamingContext c)
{
Console.WriteLine("OnDeserialized: {0}", a);
a = 1;
}
[OnDeserializing]
void OnDeserializing(StreamingContext c)
{
Console.WriteLine("OnDeserializing: {0}", a);
a = 2;
}
[OnSerialized]
void OnSerialized(StreamingContext c)
{
Console.WriteLine("OnSerialized: {0}", a);
a = 3;
}
[OnSerializing]
void OnSerializing(StreamingContext c)
{
Console.WriteLine("OnSerializing: {0}", a);
a = 4;
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
void Method(Data d);
}
public class Service : IService
{
public void Method(Data d)
{
Console.WriteLine("Method: {0}", d.a);
}
}
class Program
{
static void Main(string[] args)
{
string address = "https://localhost:8000/";
Binding binding = new BasicHttpBinding();
ServiceHost host = new ServiceHost(typeof(Service));
host.AddServiceEndpoint(typeof(IService), binding, address);
host.Open();
ChannelFactory<IService> factory = new ChannelFactory<IService>(binding);
factory.Open();
IService proxy = factory.CreateChannel(new EndpointAddress(address));
Data d = new Data();
d.a = 5;
proxy.Method(d);
factory.Close();
host.Close();
Console.ReadLine();
}
}
You can try running the program to see the value of the data member at various points in time. If you're still confused, here's exactly what's going on.
- The data member on the client is set to 5.
- OnSerializing is called and changes the data member from 5 to 4.
- OnSerialized is called and changes the data member from 4 to 3. The service doesn't see this because the data has already been serialized. This only changed the value of the data member on the client.
- The service is called.
- The service initializes the type to its default value, which for the data member is 0.
- OnDeserializing is called and changes the data member from 0 to 2.
- Deserialization actually occurs and replaces the current value of the data members with the value sent by the client. This means that the data member has changed from 2 back to 4.
- OnDeserialized is called and changes the data member from 4 to 1.
- The service method is called and sees the value of the data member as 1.
Next time: Keeping up with Extension Versions
Comments
Anonymous
November 19, 2007
How does the data contract get instantiated without a constructor being called?Anonymous
November 19, 2007
Hi Rob, I believe it's this method that gets called to instantiate the object. http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspxAnonymous
November 19, 2007
Message replay is an attack where a message is presented to a processor more than once in the hopes ofAnonymous
November 19, 2007
Very intresting, what i dont understand is why is the service instansitated until and unless the OnSerialized method is completed, shouldn't the value from the client be passed after the OnSerialized method is completed.Anonymous
November 20, 2007
Hi Nen, You're actually correct. The service is not instantiated until OnSerialized returns. I didn't notice that I had those out of order when I drafted the list.