Datacontract Serialization Attributes Of Jesus

  • DataContract and DataMember Attributes This sample shows how.NET Framework attributes such as DataContractAttribute, DataMemberAttribute and NonSerializedAttribute can be used with Json.NET instead of Json.NET's own attributes.
  • XmlSerializer vs DataContractSerializer: Serialization in Wcf Posted by Dan Rigsby on March 7th, 2008 The XmlSerializer has been in.Net since version 1.0 and has served us well for everything from Remoting, Web Services, serializing to a file, etc. However in.Net 3.0 the DataContractSerializercame along.

You can also explicitly create a data contract by using DataContractAttribute and DataMemberAttribute attributes. This is normally done by applying the DataContractAttribute attribute to the type. This attribute can be applied to classes, structures, and enumerations.

Recently I have been messing around with figuring out how to serialize some data back & forth between two applications. The code in particular leveraged several interfaces, classes with readonly properties, & generics. This caused a couple problems with serialization which I thought might be useful to share for others that run into a similar problem.

C# Datacontract Attribute

Datacontract serialization attributes of jesus christ

Take for instance the following code:

staticclassProgram
{
publicstaticvoid Main()
{
Class1 m = newClass1(newMyClass<string>('Test'));
string xml = m.Serialize();
Class1 m2 = Class1.Deserialize(xml);
Debug.Assert(m.Value.ToString() m2.Value.ToString());
}
}
[Serializable]
publicclassMyClass<T> where T : IComparable
{
readonly T item;
public T Item { get { return item; } }
public MyClass(T obj)
{
item = obj;
}
}
[Serializable]
publicclassClass1
{
public Class1(object val)
{
value = val;
}
publicstring Serialize()
{
XmlSerializer serializer = newXmlSerializer(typeof(Class1));
StringWriter writer = newStringWriter();
serializer.Serialize(writer, this);
writer.Close();
return writer.ToString();
}
publicstaticClass1 Deserialize(string xml)
{
XmlSerializer serializer = newXmlSerializer(typeof(Class1));
StringReader sr = newStringReader(xml);
Class1 item = (Class1)serializer.Deserialize(sr);
return item;
}
readonlyobject value;
publicobject Value { get { return value; } }
}

Parameterless Constructor

If you run this through & try to serialize & then deserialize you will run into a problem just serializing this. The first error you will hit is:

System.InvalidOperationException was unhandled
Message=There was an error generating the XML document.
Source=System.Xml
StackTrace:
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o)
at MyNamespace.Class1.Serialize()
at MyNamespace.Program.Main()
InnerException: System.InvalidOperationException
Message=MyNamespace.MyClass`1[System.String] cannot be serialized because it does not have a parameterless constructor.
Source=System.Xml

Xml Serialization requires you to have a parameterless constructor, so you can either add one, or switch to using WCF DataContract Serialization. This is as simple as changing the attribute on your Classes from [Serializable] to [DataContract] and then updating your Serialize & Deserialize methods. This will allow you to successfully serialize & deserialize the objects without an exception.

[DataContract]
publicclassMyClass<T> where T : IComparable
{
readonly T item;
public T Item { get { return item; } }
public MyClass(T obj)
{
item = obj;
}
}
[DataContract]
publicclassClass1
{
public Class1(object val)
{
value = val;
}
publicstring Serialize()
{
StringBuilder xml = newStringBuilder();
DataContractSerializer serializer = newDataContractSerializer(typeof(Class1));
using (XmlWriter xw = XmlWriter.Create(xml))
{
serializer.WriteObject(xw, this);
xw.Flush();
return xml.ToString();
}
}
publicstaticClass1 Deserialize(string xml)
{
Class1 newItem;
DataContractSerializer serializer = newDataContractSerializer(typeof(Class1));
StringReader textReader = newStringReader(xml);
using (XmlReader xr = XmlReader.Create(textReader))
{
newItem = (Class1)serializer.ReadObject(xr);
}
return newItem;
}
readonlyobject value;
publicobject Value { get { return value; } }
}

Serializing Read-only Properties

Next you will his the Debug.Assert which was a check to ensure we are serializing the read-only property was correctly being populated & in this case it is not. The reason being is that XmlSerialization will automatically attempt to serialize all public properties, but WCD DataSerialization does not automatically attempt to serialize any properties. So you need to decorate any item you want serialized with a [DataMember] tag. This is great because now for readonly properties you can just mark the underlying private data as the DataMember.

[DataMember]
readonlyobject value;
publicobject Value { get { return value; } }

Serializing Generics

The next problem you will hit is a SerializationException about not being able to Serialize the generic MyClassOfString, aka MyClass<string>

System.Runtime.Serialization.SerializationException was unhandled
Message=Type 'MyNamespace.MyClass`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' with data contract name 'MyClassOfstring:
http://schemas.datacontract.org/2004/07/MyNamespace' is not expected. Consider using a DataContractResolver or 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.
Source=System.Runtime.Serialization

C# Datamember Attribute

To resolve this you will need to use the KnownType attribute & there are a couple options:

  1. Generically implement serialization
  2. Explicitly list the known types

Generic KnownType

Generic serialization is nice as the serialize since you don’t have to decorate your code with the various possible classes used for your generic. To implement it you add the KnownTypes attribute to your class with a string of the method name to call.

[DataContract]
[KnownType('GetTypes')]
publicclassMyClass<T> where T : IComparable
{
readonly T item;
public T Item { get { return item; } }
public MyClass(T obj)
{
item = obj;
}
staticType[] GetTypes()
{
returnnewType[] { typeof(MyClass<T>) };
}
}

Explicit KnownType

If you do the above then you will wind up with an exception during deserialization now since Class1 does not how to deserialize MyClassOfString. As the deserializer you will need to explictly state what types you expect. In this case you can do it with a single attribute on the top.

[DataContract]
[KnownType(typeof(MyClass<string>))]
publicclassClass1

Final Results

At this point the class will successfully serialize & deserialize fully. Due to the nature of my example, the step of using the GetTypes method is not required since I am doing both serialization & deserialization in Class1, but it is useful when that is not the case.

staticclassProgram
{
publicstaticvoid Main()
{
Class1 m = newClass1(newMyClass<string>('Test'));
string xml = m.Serialize();
Class1 m2 = Class1.Deserialize(xml);
Debug.Assert(m.Value.ToString() m2.Value.ToString());
}
}
[DataContract]
[KnownType('GetTypes')]
publicclassMyClass<T> where T : IComparable
{
readonly T item;
public T Item { get { return item; } }
public MyClass(T obj)
{
item = obj;
}
staticType[] GetTypes()
{
returnnewType[] { typeof(MyClass<T>) };
}
}
[DataContract]
[KnownType(typeof(MyClass<string>))]
publicclassClass1
{
public Class1(object val)
{
value = val;
}
publicstring Serialize()
{
StringBuilder xml = newStringBuilder();
DataContractSerializer serializer = newDataContractSerializer(typeof(Class1));
using (XmlWriter xw = XmlWriter.Create(xml))
{
serializer.WriteObject(xw, this);
xw.Flush();
return xml.ToString();
}
}
publicstaticClass1 Deserialize(string xml)
{
Class1 newItem;
DataContractSerializer serializer = newDataContractSerializer(typeof(Class1));
StringReader textReader = newStringReader(xml);
using (XmlReader xr = XmlReader.Create(textReader))
{
newItem = (Class1)serializer.ReadObject(xr);
}
return newItem;
}
[DataMember]
readonlyobject value;
publicobject Value { get { return value; } }
}
-->

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. A data contract precisely defines, for each parameter or return type, what data is serialized (turned into XML) to be exchanged.

Data Contract Basics

Windows Communication Foundation (WCF) uses a serialization engine called the Data Contract Serializer by default to serialize and deserialize data (convert it to and from XML). All .NET Framework primitive types, such as integers and strings, as well as certain types treated as primitives, such as DateTime and XmlElement, can be serialized with no other preparation and are considered as having default data contracts. Many .NET Framework types also have existing data contracts. For a full list of serializable types, see Types Supported by the Data Contract Serializer.

New complex types that you create must have a data contract defined for them to be serializable. By default, the DataContractSerializer infers the data contract and serializes all publicly visible types. All public read/write properties and fields of the type are serialized. You can opt out members from serialization by using the IgnoreDataMemberAttribute. You can also explicitly create a data contract by using DataContractAttribute and DataMemberAttribute attributes. This is normally done by applying the DataContractAttribute attribute to the type. This attribute can be applied to classes, structures, and enumerations. The DataMemberAttribute attribute must then be applied to each member of the data contract type to indicate that it is a data member, that is, it should be serialized. For more information, see Serializable Types.

Example

The following example shows a service contract (an interface) to which the ServiceContractAttribute and OperationContractAttribute attributes have been explicitly applied. The example shows that primitive types do not require a data contract, while a complex type does.

Datacontract Serialization Attributes Of Jesus

The following example shows how a data contract for the MyTypes.PurchaseOrder type is created by applying the DataContractAttribute and DataMemberAttribute attributes to the class and its members.

Notes

The following notes provide items to consider when creating data contracts:

Human Attributes Of Jesus

  • The IgnoreDataMemberAttribute attribute is only honored when used with unmarked types. This includes types that are not marked with one of the DataContractAttribute, SerializableAttribute, CollectionDataContractAttribute, or EnumMemberAttribute attributes, or marked as serializable by any other means (such as IXmlSerializable).

  • You can apply the DataMemberAttribute attribute to fields, and properties.

  • Member accessibility levels (internal, private, protected, or public) do not affect the data contract in any way.

  • The DataMemberAttribute attribute is ignored if it is applied to static members.

  • During serialization, property-get code is called for property data members to get the value of the properties to be serialized.

  • During deserialization, an uninitialized object is first created, without calling any constructors on the type. Then all data members are deserialized.

  • During deserialization, property-set code is called for property data members to set the properties to the value being deserialized.

  • For a data contract to be valid, it must be possible to serialize all of its data members. For a full list of serializable types, see Types Supported by the Data Contract Serializer.

    Generic types are handled in exactly the same way as non-generic types. There are no special requirements for generic parameters. For example, consider the following type.

Attributes Of Holy Spirit

This type is serializable whether the type used for the generic type parameter (T) is serializable or not. Because it must be possible to serialize all data members, the following type is serializable only if the generic type parameter is also serializable, as shown in the following code.

Datacontract Serialization Attributes Of Jesus List

For a complete code sample of a WCF service that defines a data contract see the Basic Data Contract sample.

Datacontract Serialization Attributes Of Jesus

See also