C# Serialization

SOAP Serialization with C# and .NET

Posted on Updated on

In the previous post, we discussed binary serialization with C# and .NET. In this short article we are going to dive into some specific examples of use of the SoapFormatter class to SOAP serialize objects to XML and deserialize from XML back into objects.

We will discuss SOAP a little later in this article 🙂

SOAP Serialization with the SoapFormatter class

To get started, let’s create a simple class, add some attributes to help us control how properties are serialized, then we’ll serialize and deserialize the object.

To get started, let’s create a C# Console Application that we will call SoapSerializationSample.

Create the Soap Serialization Sample Console project
Create the Soap Serialization Sample Console project

Next, we will add a class to the project. We will call this class Sample.

Let’s now add two properties – Name and Value as shown below then decorate the class with the Serializable attribute.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SoapSerializationSample
{
    [Serializable]
    public class Sample
    {
        public string Name
        {
            get;
            set;
        }

        public Int32 Value
        {
            get;
            set;
        }
    }
}

As you can see, this class is very simple and is a great starting point for examining SOAP serialization.

The Serializable attribute signals the .NET runtime that instances of this class can be serialized. To use serialization, this attribute must be in place at the class level.

Before we write the serialization code, let’s first add the references shown in the illustration below:

System.Serialization.Runtime References
System.Serialization.Runtime References

Next, let’s add the following using statements to our Program class:

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

In our Program.cs class’s Main() method, we are going to write some simple code that uses the SoapFormatter to serialize an instance of our Sample object into a Soap XML stream.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;

namespace SoapSerializationSample
{
    class Program
    {
        static void Main(string[] args)
        {
            //create an instance of our Sample class
            //which we will serialize below
            Sample sample = new Sample();
            sample.Name = "John Nelson";
            sample.Value = 44;

            //create a FileStream to accept the output
            FileStream fileStream = new FileStream(@"c:\temp\MySoapFile.dat", FileMode.Create);

            //create a SoapFormatter to serialize the object
            SoapFormatter formatter = new SoapFormatter();

            //serialize the object to the .dat file
            formatter.Serialize(fileStream, sample);
        }
    }
}

When we press F5 and run the application, the SoapFormatter serializes the Sample object to our MySoapFile.dat file. If we open this file in Visual Studio, we see something that looks like this:

SoapFormatter XML Output
SoapFormatter XML Output

So, some of you are probably looking at this output and screaming “this is NOT well-formed XML!” and you are right! This file does not contain an xml declaration does not contain opening and closing xml tags. Though an in-depth discussion of SOAP is well beyond the purpose and scope of this article, it will be beneficial to briefly discuss the parts of a SOAP message.

What is SOAP?

Soap is an acronym for Simple Object Access Protocol. It is basically an XML-based protocol for transmitting data between computers and is designed for for data communication via the internet and provides the transport mechanism for web services. SOAP is language and platform independent.

SOAP Message Structure

SOAP messages are encoded as XML documents. These documents begin with a mandatory <Envelope> element and may or may not contain a <Header> element. The <Body> element is mandatory for all SOAP messages, so we would expect to always see that. A <Fault> element may or may not be contained within the <Body> element and is used to provide information about exceptions or errors that may have occurred while the message was processed.

<Envelope> Element

The <Envelope> element is the start and end of the message. The entire SOAP message is contained within the <Envelope> element. Every <Envelope> element must contain exactly one <Body> element – no exceptions! The <Envelope> will change if the version of the message changes.

<Header> Element

<Header> elements are optional within the <Envelope> element and there can be multiple <Header> elements in a SOAP message.

<Body> Element

The <Body> element contains the actual data being transmitted in the SOAP message. You can think of it as the “guts” of the message or the payload of the message.

<Fault> Element

If you have ever worked with WCF, you are familiar with the FaultExceptions. When an error occurs during processing by a web service, information pertaining to that error can be encapsulated within a <Fault> block. If a <Fault> element is included in a SOAP message, there can only be one.

Learning More About SOAP

If you are interested in learning more about the SOAP standard, try this link.

Deserializing with the SoapFormatter

Deserializing with the SoapFormatter is as simple as serializing. See the code below:

//create a FileStream to open the .dat file
FileStream fileStream = new FileStream(@"c:\temp\MySoapFile.dat", FileMode.Open);

//create a SoapFormatter to deserialize the object
SoapFormatter formatter = new SoapFormatter();

//serialize the object to the .dat file
Sample deserializedSample = (Sample)formatter.Deserialize(fileStream);

//show the object properties
Console.WriteLine("The deserialized object:");
Console.WriteLine(String.Format("Name: {0}", deserializedSample.Name));
Console.WriteLine(String.Format("Value: {0}", deserializedSample.Value.ToString()));

Console.Read();

When we press F5 and run our application, we see the values of our object displayed in the console window:

SoapFormatter.Deserialize()
SoapFormatter.Deserialize()

XML Serialization with C# and .NET

Posted on Updated on

In the previous post, we discussed the basics of serialization in .NET. In this short article we are going to dive into some specific examples of use of the XmlSerializer to serialize objects to XML and deserialize from XML back into objects 🙂

XML Serialization with the System.Xml.Serialization.XmlSerializer class

To get started, let’s create a simple class, add some attributes to help us control how properties are serialized, then we’ll serialize and deserialize the object.

To get started, let’s create a C# Console Application that we will call SerializationSample.

Create the Serialization Sample Console Application
Create the Serialization Sample Console Application

Next, we will add a class to the project. We will call this class Sample.

Let’s now add two properties – Name and Value as shown below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SerializationSample
{
    public class Sample
    {
        public string Name
        {
            get;
            set;
        }

        public Int32 Value
        {
            get;
            set;
        }
    }
}

As you can see, this class is very simple and is a great starting point for examining Xml serialization.

In our Program.cs class’s Main() method, we are going to write some simple code that uses the XmlSerializer to serialize an instance of our Sample object into an XML stream.

static void Main(string[] args)
{
    //let's first instantiate our Sample object
    //and set its two properties
    Sample sample = new Sample();
    sample.Name = "John Nelson";
    sample.Value = 44;

    //next, create an instance of an XmlSerializer
    //we will use the Type constructor for this example
    XmlSerializer serializer = new XmlSerializer(typeof(Sample));

    //serialize the object to the Console
    serializer.Serialize(Console.Out, sample);

    Console.ReadLine();
}

When we press F5 and run the console application, our console window displays the resulting XML. See the following illustration.

XMLSerializer.Serialize Output
XMLSerializer.Serialize Output

So when we look at the resulting XML, we see the standard xml declaration followed by the opening tag for our Sample object, an XML namespace (xmlns) attribute, and the values of the two properties in our object. Pretty simple, right?

XML Namespaces

Though my intent in this article is to discuss XML serialization and not XML and its accompanying concepts, we do need to briefly talk about the concept of XML namespaces. XML namespaces provide a couple of things in our generated XML. First, they remove any ambiguity between two or more elements that happen to have the same name. Second, they are useful for grouping elements that relate and adhere to a common “idea” together.

A namespace is identified and conveyed via a uri. So what does that mean? Well, I could define a namespace that I could use for all of my XML “objects” based on http://johnlnelson.com. I could for the sake of this example specify the namespace to be https://johnlnelson.com/namespaces/sample. It is a safe assumption that anyone who produces XML for the purpose of transmitting it via HTTP would do this via a domain, such as johnlnelson.com.

Armed with this little bit of knowledge, let’s modify our code to specify our own namespace and prefix.

static void Main(string[] args)
{
    //let's first instantiate our Sample object
    //and set its two properties
    Sample sample = new Sample();
    sample.Name = "John Nelson";
    sample.Value = 44;

    //next, create an instance of an XmlSerializer
    //we will use the Type constructor for this example
    XmlSerializer serializer = new XmlSerializer(typeof(Sample));

    //specify our namespace
    XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
    namespaces.Add("jln", "https://johnlnelson.com/namespaces/sample");

    //serialize the object to the Console
    //with our specified namespace
    serializer.Serialize(Console.Out, sample, namespaces);

    Console.ReadLine();
}

Pay attention to lines 14-15 and the new overload of the Serialize() method in line 19.

We created an instance of an XmlSerializerNamespaces object and added one prefix/namespace combination. The prefix I chose is “jln” and my namespace is https://johnlnelson.com/namespaces/sample.

When we press F5 to launch the application and view our XML output, we see our own namespace in the XML.

XMLSerializer.Serialize Output with Namespace
XMLSerializer.Serialize Output with Namespace

Pretty simple? Sure it is. Now let’s take a look at the encoding attribute in our xml document tag. What if we don’t want to use the default IBM437 encoding? We can do that too, but the code is slightly more involved (but not too bad).

Let’s modify our serialization code to look like this:

//let's first instantiate our Sample object
//and set its two properties
Sample sample = new Sample();
sample.Name = "John Nelson";
sample.Value = 44;

//next, create an instance of an XmlSerializer
//we will use the Type constructor for this example
XmlSerializer serializer = new XmlSerializer(typeof(Sample));

//specify our namespace
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("jln", "https://johnlnelson.com/namespaces/sample");

//create an XmlWriterSettings object to specify the
//encoding and the indentation
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = new UTF8Encoding();
settings.Indent = true;

//create an XmlWriter that utilizes a StringWriter to
//build the output, then write that to the Console window
using (StringWriter stringWriter = new StringWriter())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
    {
        serializer.Serialize(xmlWriter, sample, namespaces);
        Console.Write(stringWriter);
    }
}

Console.ReadLine();

You will see quite a few changes from lines 17 to 30. We will discuss the changes in a bit, but first let’s press F5 and run our code! The console window will now look like this:

XMLSerializer.Serialize() Output
XMLSerializer.Serialize() Output

Okay, so what’s going on here? First, in order to take the level of control over our encoding, we had to initiate the help of a StringWriter and an XmlWriter. We created an XmlWriterSettings object to allow us to specify the encoding and the indentation for our XML output. Then we wrapped the XmlWriter in a StringWriter which we then used to send our output to the Console window.

We won’t go into too much detail about StringWriters and XmlWriters in this article, but let’s just take from this the fact that it is possible to exert varying levels of control over our XML serialization.

Controlling How We Serialize

Before we jump into deserialization, let’s hop back to our Sample class and take a look at some ways we can control how instances of this type are XML serialized. This sample class has two properties: Name and Value. As it stands now, both properties get serialized when we call the XmlSerializer.Serialize() method. Let’s look at some ways we can control this.

System.Xml.Serialization.XmlIgnoreAttribute

Using the XmlIgnore attribute we can instruct the XmlSerializer to ignore public fields or properties when XML serialization takes place. For this example, let’s add an XmlIgnore attribute to the Value property as shown below:

[XmlIgnore]
public Int32 Value
{
    get;
    set;
}

By adding this simple attribute, the XmlSerializer will not serialize this property. Let’s press F5 and give it a try.

When we place a breakpoint and view the XML output in the XML view window, we notice that the Value property did NOT get serialized.

XmlSerializer.Serialize() method with Value property ignored
XmlSerializer.Serialize() method with Value property ignored

Pretty simple, right?

System.Xml.Serialization.XmlElementAttribute

What if we want to serialize a property, but we want the XmlElement to have a name other than the actual name in the object? This is equally simple by decorating that property with an XmlElement attribute. See the code below.

[XmlElement (ElementName="TheValue")]
public Int32 Value
{
    get;
    set;
}

This attribute instructs the XmlSerializer to serialize the property, but to name the XmlElement “TheValue”. Again, we place a breakpoint and view the output:

XmlSerializer.Serialize() method with XmlElement attribute on Value property
XmlSerializer.Serialize() method with XmlElement attribute on Value property

As we can see in the output, the Value field is serialized as TheValue. Pretty simple.

There are more customization options available through attributes, but we are not going to cover all of them here. This MSDN resource is an excellent source of information.

Deserializing XML with C#

Now that we have discussed XML serialization, let’s look quickly at how to deserialize our XML and re-inflate a Sample object.

We will modify the code in our Program class’s Main() method to look like this:

//let's first instantiate our Sample object
//and set its two properties
Sample sample = new Sample();
sample.Name = "John Nelson";
sample.Value = 44;

//next, create an instance of an XmlSerializer
//we will use the Type constructor for this example
XmlSerializer serializer = new XmlSerializer(typeof(Sample));

//specify our namespace
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("jln", "https://johnlnelson.com/namespaces/sample");

//serialize the object to a StringWriter
//with our specified namespace
StringWriter writer = new StringWriter();
serializer.Serialize(writer, sample, namespaces);

//for our subsequent deserialization, we will
//get the StringWriter's underlying StringBuilder
string xml = writer.GetStringBuilder().ToString();

//we will create a new StringReader using
//the xml string created above
TextReader reader = new StringReader(xml);

//we will deserialize the reader and cast
//the resulting object to a Sample type
Sample deserialized = (Sample)serializer.Deserialize(reader);

//finally, we will write our object to the Console
Console.WriteLine("We have deserialized our object");
Console.WriteLine(String.Format("Name: {0}", deserialized.Name));
Console.WriteLine(String.Format("Value: {0}", deserialized.Value.ToString()));
Console.WriteLine("That was cool!");

Console.ReadLine();

The commentary in the code is pretty straightforward. We serialized our object into a StringWriter then got that object’s underlying StringBuilder and got its string representation via the xml string object. Then we created a StringReader to utilize the XML string value as an input to our XmlSerializer.Deserialize() method. We immediately cast the return object to the Sample type because we knew that it would work. In most situations like this, should NOT attempt such a cast. Instead, you should stuff the result into an object, then check for null BEFORE attempting the cast. That is just a good programming practice.

When we press F5 to run the application, we see the following output:

XMLSerializer.Deserialize() Output
XMLSerializer.Deserialize() Output

In the next article, we will take a quick look at binary serialization.