WCF's NetDataContractSerializer

Service Station, by Aaron Skonnard

Syndication

Before the Feb bits, WCF came with one new serializer called DataContractSerializer (DCS). However, DCS came with two modes: SharedContract and SharedType. The modes reflected whether you were planning to share the schema contract across the wire or the .NET type information respectively.
 
In general, sharing the schema contract is the preferred and recommended approach because it loosens the coupling across the wire by conforming to the SO tenet "share schema and contract, not implementation". Nevertheless, WCF still wants to support .NET remoting-style applications where maintaining type fidelity across the wire is important...hence, the SharedType mode. With SharedType, the .NET type information is serialized into each message so the same type can be used on the other side.
 
As of the Feb CTP, the WCF team decided to split these two modes into separate classes - so now you have DataContractSerializer (SharedContract) and NetDataContractSerializer (SharedType). The WCF folks want to encourage folks to use the "shared contract" model as much as possible so the DCS is the default serializer throughout the framework -- contracts always use DCS unless overriden with a serializer format attribute. 
 
For example, if you'd prefer to use XmlSerializer instead of DCS, you can annotate the interface or individual methods with [XmlSerializerFormat]. However, because the WCF team is trying to discourage the use of NDCS, there is no such attribute for enabling it, which is probably a good thing. If you wish to use NDCS with your contracts, you'll have to write a custom behavior to inject it at the right time. Here's an example:
 

public class NetDataContractFormat : Attribute, IOperationBehavior

{

    public void AddBindingParameters(OperationDescription description,

        BindingParameterCollection parameters)

    {

    }

    public void ApplyClientBehavior(OperationDescription description,   

        ClientOperation proxy)

    {

        ReplaceDataContractSerializerOperationBehavior(description);

    }

    public void ApplyDispatchBehavior(OperationDescription description,

        DispatchOperation dispatch)

    {

        ReplaceDataContractSerializerOperationBehavior(description);

    }

    public void Validate(OperationDescription description)

    {

    }

    private static void ReplaceDataContractSerializerOperationBehavior(

        OperationDescription description)

    {

        DataContractSerializerOperationBehavior dcsOperationBehavior =

            description.Behaviors.Find<

                DataContractSerializerOperationBehavior>();

        if (dcsOperationBehavior != null)

        {

            description.Behaviors.Remove(dcsOperationBehavior);

            description.Behaviors.Add(new

             NetDataContractSerializerOperationBehavior(description));

        }

    }

    public class NetDataContractSerializerOperationBehavior :

        DataContractSerializerOperationBehavior

    {

        public NetDataContractSerializerOperationBehavior(

            OperationDescription operationDescription) :

                base(operationDescription) { }

        public override XmlObjectSerializer CreateSerializer(

            Type type, string name, string ns, IList<Type> knownTypes)

        {

            return new NetDataContractSerializer();

        }

 

        public override XmlObjectSerializer CreateSerializer(Type type,

            XmlDictionaryString name, XmlDictionaryString ns,

            IList<Type> knownTypes)

        {

            return new NetDataContractSerializer();

        }

    }

}

 
This solution basically overrides the behavior of the built-in DataContractSerializerOperationBehavior, which is called by the runtime to create the serializer when needed (see CreateSerializer).
 
You can grab the complete source file from here.
 

Posted Apr 21 2006, 12:42 PM by Aaron Skonnard
Filed under: ,

Comments

Miscellaneous Debris wrote WCF Serialization part 1: Interfaces, Base classes and the NetDataContractFormatSerializer
on 07-31-2006 2:30 PM
One of WCF&#39;s goals is interoperability with standard protocol stacks, like WSE or other WS-* implementations.
Miscellaneous Debris wrote WCF Serialization part 1: Interfaces, Base classes and the NetDataContractFormatSerializer
on 07-31-2006 3:16 PM
One of WCF's goals is interoperability with standard protocol stacks, like WSE or other WS-* implementations....
Andres G Vettori wrote re: WCF's NetDataContractSerializer
on 09-19-2006 12:04 PM
Hi Aaron, I understand why the WCF team wants to discourage the use of SharedType communication, but there are lots of cases where it make sense in a closed system when you don't need to expose anything to the outside world (Remoting).
If you guys make the effort creating the NetDataContractSerializer I don't understand why you don't make easier to use it.
I guess this attribute [NetDataContractFormat] should be part of the standard WCF bits, despite the clear guidance telling you when is appropiate to use it.
Any chance to get this included in the final bits?

Bets regards,
Andrés.
R Martinon wrote re: WCF's NetDataContractSerializer
on 01-17-2007 4:21 PM
Thanks a lot for sharing this, Aaron. It was pretty helpful to my current project, just when I was losing faith in doing proper OO with WCF in my closed system scenario.

This deserves more visibility.

(obviously this attribute should be in the framework)
Mehran Nikoo's Blog wrote Serialisation and Encoding in WCF
on 02-05-2007 10:13 AM
Although serialisation and encoding can be considered as closely related subjects in messaging, but from
Mehran Nikoo's Blog wrote Serialisation and Encoding in WCF
on 02-05-2007 10:13 AM
Although serialisation and encoding can be considered as closely related subjects in messaging, but from
Bartol wrote re: WCF's NetDataContractSerializer
on 03-15-2007 10:30 AM
Thanks for the code.
Some issues have arisen though, with which your help would be greatly appreciated:

1. Instead of applying the [NetDataContractFormat] attribute to contract methods, I would prefer to setup the NetDataContractFormat behavior explicitly
by adding it to the Behaviors collection of each operation in the ServiceEndpoint.Contract.Operations prior to opening a ServiceHost and creating a client channel. For some reason this doesn't work however. The ApplyDispatchBehavior and ApplyClientBehavior methods do get called but the CreateSerializer method does not??

2. When I do apply the [NetDataContractFormat] to all [OperationContract]s in my interface and also apply the [OperationBehavior()] attribute to the service implementation method, even stranger behavior than from issue #1 occurs: the ApplyDispatchBehavior and ApplyClientBehavior methods do get called but the CreateSerializer method does not, and additionally to this, method parameter values or return values are all set at their default values (e.g. int parameter would be == 0, string would be == null...), no mather what gets sent to the method, or what the method returns. Nothing gets serialized.

What could be the problem?




Joel C wrote re: WCF's NetDataContractSerializer
on 03-15-2007 3:13 PM
I've been able to use the NetDataContract attribute successfully, EXCEPT for one thing... When I attribute my service method with: [OperationBehavior(Impersonation = ImpersonationOption.Required)], my serialized parameters are showing up as "null" on the server side. (This sounds like it could be related to Bartol's comment, since I'm applying an OperationBehavior as well.)
Joel C wrote re: WCF's NetDataContractSerializer
on 03-15-2007 3:40 PM
Actually, I think I solved my problem (and maybe for Bartol, too)... Basically you change ReplaceDataContractSerializerOperationBehavior to be:

private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsOperationBehavior != null)
{
int idx = description.Behaviors.IndexOf(dcsOperationBehavior);
description.Behaviors.Remove(dcsOperationBehavior);
description.Behaviors.Insert(idx, new NetDataContractSerializerOperationBehavior(description));
}
}

(... presumably the order must be maintained in the Behaviors collection) After doing this, my test harness suddenly works with Impersonation turned on!
Joel C wrote re: WCF's NetDataContractSerializer
on 03-15-2007 8:06 PM
SIGH! I may need to take back my last reply... it seems to work in one test setting but not in the "real" application I'm trying to get working, despite being quite similar.
Joel C wrote re: WCF's NetDataContractSerializer
on 03-16-2007 7:37 AM
Please see: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1356698&SiteID=1&mode=1

(I think I resolved the problem I noted yesterday.)
Nicholas Allen's Indigo Blog wrote Replacing the Serializer, Part 2
on 05-21-2007 6:42 PM
Last time on the topic of serialization, we were looking at some issues with commonly replicated sample
vtcoder wrote re: WCF's NetDataContractSerializer
on 02-04-2008 10:14 AM
Thank God someone else is shouting about WCF and Microsoft trying to prescribe the best architecture via SOA. I'm so sick of hearing SOA as the answer to every distributed problem. If I'm developing a 'closed system' and my 'data contracts' change, I WANT to recompile and retest all other modules. And in this situation it makes no sense to limit communication to a pure SOA style. It makes perfect sense to pass managed types. WCF really needs to account for this area of development (enterprise applications, not disparate IT solutions, but one large, versioned, application that may want to take advantage of WCFs plumbing without being forced into SOA-land, and in which tighter coupling may make perfect sense).

Sorry for the rant, but it is nice to see others mention this, now I feel better :)

Having said all of that, does anyone know if the NetDataContractSerializer became a 1st class citizen for the release or not?
Inv wrote re: WCF's NetDataContractSerializer
on 04-03-2008 2:50 PM
Vtcoder is right. I'm thinking about using the good old remoting. WCF sucks so much in this area. MS suggested KnownTypeAttribute is absolutely inacceptable, I want users of my library to be able to submit an derived instance to my service, and the service then serves this instance to clients.
Alistair Rigney wrote re: WCF's NetDataContractSerializer
on 04-15-2008 12:04 AM
Hi Guys,
I was trying to use a type as a parameter to my generic WCF web service that uses reflection to reflect on an arbitary business layer. I got around this problem by just passing the assembly qualified type name and then just converting this to the required type with GetType. It works a treat.

Regards,
Alistair
Eran wrote re: WCF's NetDataContractSerializer
on 05-16-2008 6:19 AM
Hi hi,
Finally a solution for 'closed systems'!
Question, this article describes passing interface. what about returning interface.

I get on the client side the following exception:

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:id. The InnerException message was 'Error in line 1 position 120. XML 'Element' 'http://tempuri.org/:id' does not contain expected attribute 'http://schemas.microsoft.com/2003/10/Serialization/:Type'. The deserializer has no knowledge of which type to deserialize. Check that the type being serialized has the same contract as the type being deserialized.'. Please see InnerException for more details.
Eran wrote Replay to myself :)
on 05-16-2008 7:04 AM
Hi again,
i found a topic which describes how to replace the serializer in the client channel.http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3282261&SiteID=1

Thanks, it saved me!
Mangleeswararan wrote re: WCF's NetDataContractSerializer
on 06-27-2008 3:43 AM

KnownType Issue

We are trying to use a "Known Type" feature in WCF service.

We have two separate components, one for base class (DataContractBase component) and another one for derived classes (DataContract). The DataContract classes are derived from base class of DataContractBase component.

DataContractBase Component

namespace DataContractBase

{    

   [DataContract]

   public abstract class User

   {

   }

}

EntityClasses Component

namespace EntityClasses

{

   [Serializable]

   [DataContract]

   public class EmployeeUser : User

   {

       [DataMember]

       public bool IsMember { get; set; }

       [DataMember]

       public string Name { get; set; }

       [DataMember]

       public int Age { get; set; }

   }

}

We have defined the WCF service interface where the method parameter is base class type. Our client application will consume the WCF service interface and send out the business entities to WCF service. These business entities are part of the DataContract component.

namespace CustomerServiceInterface

{

   [ServiceContract]

   public interface IService1

   {

       [OperationContract]        

       User[] Create(User[] usr);

       [OperationContract]        

       User[] Update(User[] usr);

   }

}

namespace CustomerService

{

public class Service1 : IService1

{

        public User[] Create(User[] usr)

        {                

            //Service Implementation

       }

}

}

We tried both KnownType attribute and KnownType config to define the list of KnownTypes in the DataContractBase component and WCF Service config file. But we got the following error in the both the cases.

"There was an error while trying to serialize parameter http://tempuri.org/:usr. The InnerException message was 'Type 'EntityClasses.EmployeeUser' with data contract name 'EmployeeUser:schemas.datacontract.org/.../EntityClasses& is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details."

But when we grouped both the DataContractBase and DataContract components together, atleast the KnownType attribute defenition started working. But it didn't work when we specified the KnownType details in config file.

Due to design constraint we cannot keep the base class and derived classes together in a single component. It should be put in two different components like DataContractBase and DataContract.

We were unable to resolve this issue.

Can someone please help us to resolve this issue. Any pointer will be very much appreciated.

Maverick wrote re: WCF's NetDataContractSerializer
on 07-30-2008 1:40 PM

Mangleeswararan,

I am facing the same problem with exact same error. Could you please let me know if you are able to resolve this issue and if yes how.

Thanks in advance.

Mr. Man wrote re: WCF's NetDataContractSerializer
on 08-12-2008 9:50 AM

I hate WCF, I am glad I never have to use it. You are making a mistake if you expose all those types around the network, this is a place you should only use interfaces, er I mean XML documents that represent source code that defines interfaces, almost. Long live XML! soon everything will be self-describing and XSLT programmers will be the new kings of everything. Is it 1999 yet?

Add a Comment

(required)  
(optional)
(required)  
Remember Me?