BizTalk Utilities CV ,   Jobs ,   Code library
 
Go to the front page to continue learning about XML or select below:

Contents

ReBlogger Contents

Previous posts in WSCF/WCF

 
 
Page 2306 of 18429

DataContracts without attributes (POCO support) in .NET 3.5 SP1

Blogger : Service Station
All posts : All posts by Service Station
Category : WSCF/WCF
Blogged date : 2008 May 13


One of the
new WCF features in .NET 3.5 SP1 is that DataContractSerializer now supports serializing types that aren’t annotated with any serialization attributes like [DataContract] or [Serializable].

If you were using DataContractSerializer prior to SP1, you had to follow the rules outline by Sowmy here. These rules illustrate that for custom classes you have a few choices. You can annotate the class with [DataContract] and [DataMember] to define an attribute-based mapping or implement IXmlSerializable to define a custom mapping. Or you can annotate the class with [Serializable] to automatically map all fields (like with .NET Remoting) or implement ISerializable to take things into your own hands (assuming IXmlSerializable wasn't used).

However, as you can see from the rules, there is no allowance for types that haven’t been annotated with one of these serialization attributes or that implement one of the serialization-related interfaces, or in other words, you can't serialize “plain old C# objects“ (POCO for short).

The support for [Serializable] provided a nice migration path for traditional .NET Remoting types, which was nice, but the lack of support for POCO types meant you couldn’t move your ASMX types over to the DataContractSerializer without sprinkling a bunch of new attributes on them.

With .NET 3.5 SP1 you can serialize any C# object even if it doesn’t come with any serialization attributes. For example, the following Person type is now serializable by default:

namespace SerializationSp1

{

    public class Person

    {

        private string id;

        public string Id { get { return id; } set { id = value; } }

        public string Name;

        public Person Spouse;

    }

    ...

}

 

For POCO types, DataContractSerializer only includes the public read/write fields and properties into the resulting XML Infoset. So in our example above, the private “id” field won’t make it into the message. Also, these types must have a public default (no argument) constructor in order to be serialized. The Person type above works find because the compiler gives us a public default constructor but if you were to add a non-default constructor, it would no longer be serializable using this approach.

With this new support, you can use virtually any C# type (with a public default constructor) in your WCF service contracts and you don’t have to worry about changing the serializer back to XmlSerializer using [XmlSerializerFormat]. For example, the following service contract works as-is in .NET 3.5 SP1:

[ServiceContract]

public interface ILookupPerson

{

    [OperationContract]

    Person GetPerson(string id);

}

 

Now let’s take a look at the serialized XML for the Person type shown above. Here’s a simple console program that uses DataContractSerializer to serialize a Person object:

class Program

{

    static void Main(string[] args)

    {

        Person p = new Person();

        p.Id = "123";

        p.Name = "Aaron";

        p.Spouse = new Person();

        p.Spouse.Id = "456";

        p.Spouse.Name = "Monica";

 

        DataContractSerializer dcs = new DataContractSerializer(typeof(Person));

        using (FileStream fs = new FileStream("person.xml", FileMode.Create))

        {

            dcs.WriteObject(fs, p);

        }

    }

}

And here’s what the resulting person.xml file looks like:

<Person xmlns="http://schemas.datacontract.org/2004/07/SerializationSp1"

        xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

  <Id>123</Id>

  <Name>Aaron</Name>

  <Spouse>

    <Id>456</Id>

    <Name>Monica</Name>

    <Spouse i:nil="true"/>

  </Spouse>

</Person>

The mapping algorithm is similar to what’s used with [DataContract] or [Serializable] – it uses the type name for the root element name, member names for the local element names, and it orders them alphabetically. It also produces a reasonable XML namespace based on the .NET namespace. The only difference is how it chooses what to put into the message – in this case it’s based on the public contract of the type. When you use this approach, you must be happy with the XML that DataContractSerializer gives you. In other words, you can’t customize the resulting XML in any way.

As soon as you place the [DataContract] attribute on the class, DataContractSerializer will only include fields/properties annotated with [DataMember] once again. For example, suppose I make the following change to the Person type by annotating it with [DataContract]:

[DataContract]

public class Person

{

    private string id;

    public string Id { get { return id; } set { id = value; } }

    public string Name;

    public Person Spouse;

}

 

If I run my console program again, the resulting person.xml now looks like this:

<Person xmlns="http://schemas.datacontract.org/2004/07/SerializationSp1"  
       
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"/>

Notice that none of the fields were serialized because they weren’t annotated with [DataMember]. Once I applied [DataContract] to Person, DataContractSerializer no longer treated it like a POCO type. The same would hold true if I annotated the type with [Serializable]. If it finds the [Serializable] attribute, it falls back to the [Serializable] mapping and only includes the fields.

To summarize, the new DataContractSerializer provides several different mechanisms for defining the serialization mapping:

1.        Simply rely on the public interface and take the default XML mapping

2.        Use [Serializable] to only include fields in the mapping

3.        Use [DataContract] and [DataMember] and apply some basic customization

4.        Use IXmlSerializable or ISerializable for advanced mapping customization

I was actually surprised to learn that they added this feature because it goes against the main reason for the original [DataContract] design (“boundaries are explicit”), at least according to the team in early design reviews. I asked for this feature (an implicit mapping) but my request was dismissed for that very reason. Despite whatever principle it may violate, I like it, because it makes it simpler for folks to get started with WCF and it provides an easier migration path for ASMX.


Read comments or post a reply to : DataContracts without attributes (POCO support) in .NET 3.5 SP1
Page 2306 of 18429

Newest posts
 

    Email TopXML