.NET serialization


Summary Although Web applications are based on inherently stateless technologies, the applications themselves are often used more than once by multiple users and can need to share information with other applications. As a result, information must often be persisted outside the application, where it can be retrieved and reused. For Web applications, it is the responsibility of the Web developer to implement a persistence mechanism to maintain information across sessions and applications. Serializing information using built-in .NET support makes persistence easy and reusable. This topic reviews the serialization options in .NET and discusses some of the limitations and best practices for utilizing serialization with the Web Application Developer Framework (ADF).

Serialization is the process of converting the state of an item (for example, an object) to a form that can be stored or transported and eventually retrieved. The Microsoft .NET Framework contains the following built-in options (classes) for serialization:
  • XmlSerializer—Serializes and deserializes objects into and from Extensible Markup Language (XML) documents
  • SoapFormatter—Serializes and deserializes an object, or an entire graph of connected objects, in Simple Object Access Protocol (SOAP) format
  • BinaryFormatter—Serializes and deserializes an object, or an entire graph of connected objects, in binary format
SoapFormatter and BinaryFormatter can successfully serialize and deserialize Web ADF objects, such as geometry, graphics datasets, and graphics layers. XmlSerializer can serialize and deserialize most Web ADF objects.
Web ADF geometry and graphics layers can be serialized using XmlSerializer.
Preparing a class for serialization using XmlSerializer often requires a significant amount of work and can be limited by architectural or technical design. As a result, you might encounter errors when serializing some Web ADF objects. See the following code:
[C#]
 < Web ADF type > cannot be serialized because it does not have a parameterless
     constructor.
In this case, XmlSerializer requires information about complex types contained by the object to be serialized. If the complex types are not null, they must have a parameterless constructor. You cannot change the source code for Web ADF classes, but you can subclass the base class and create a parameterless constructor. However, even if you define a parameterless constructor for the complex Web ADF type, another exception can be returned as shown in the following code:
[C#]
The type < Web ADDF type > was not expected. Use the XmlInclude or SoapInclude
    attribute to specify types that are unknown statically.
In general, the object to be serialized must be able to identify the complex types it references. This can be defined in the object’s class as an XmlInclude statement or provided to XmlSerializer in a Type[] array. You can manually add XmlInclude statements in the derived class or traverse the object graph and add the types to XmlSerializer on the fly. In any case, supporting each Web ADF type is a labor intensive process.
In most cases, object serialization in the Web ADF is supported through the use of the Serializable attribute and explicit implementation of IXmlSerializable. Implementing IXmlSerializable changes how the Serializable attribute functions, because it requires writing code to explicitly handle the serialization of the class to and from XML. If serialization is not explicitly handled (the implementation methods are empty), no serialization options, not even XmlSerializer, will generate content.
XmlSerializer offers the best solution for serializing to XML; however, you might experience limitations of implementation. If you cannot use XmlSerializer and still need to serialize Web ADF objects to XML, use SoapFormatter. While XML has extra overhead associated with a SOAP message, it will work.
From performance and storage perspectives, BinaryFormatter provides the most efficient means for serializing and deserializing Web ADF objects, but it is not readable.
Serialized content generated by SoapFormatter and BinaryFormatter works with SQL Server.
The following code examples demonstrate all three serialization options with a Web ADF Point:
[C#]
// Sample Web ADF Point.   
ESRI.ArcGIS.ADF.Web.Geometry.Point adfPoint = new ESRI.ArcGIS.ADF.Web.Geometry.Point
    ( - 120, 30);
// === Serialize to XML using XmlSerializer ===
System.Xml.Serialization.XmlSerializer xmlSerializer = new
    System.Xml.Serialization.XmlSerializer(adfPoint.GetType());
System.Text.StringBuilder builder = new System.Text.StringBuilder();
System.IO.StringWriter writer = new System.IO.StringWriter(builder);
xmlSerializer.Serialize(writer, adfPoint);
string xmlADFPoint = builder.ToString();
//Deserialize from XML.
System.IO.StringReader reader = new System.IO.StringReader(xmlADFPoint);
System.Xml.XmlTextReader xmlTextReader = new System.Xml.XmlTextReader(reader);
ESRI.ArcGIS.ADF.Web.Geometry.Point newXMLADFPoint = 
    (ESRI.ArcGIS.ADF.Web.Geometry.Point)xmlSerializer.Deserialize(xmlTextReader);

//=== Serialize to SOAP using SoapFormatter ===
System.Runtime.Serialization.Formatters.Soap.SoapFormatter soapFormatter = new
    System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
soapFormatter.AssemblyFormat =
    System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
soapFormatter.FilterLevel =
    System.Runtime.Serialization.Formatters.TypeFilterLevel.Low;
soapFormatter.TypeFormat =
    System.Runtime.Serialization.Formatters.FormatterTypeStyle.XsdString;
string soapADFPoint = null;
using(System.IO.MemoryStream fs = new System.IO.MemoryStream(8000))
{
    soapFormatter.Serialize(fs, adfPoint);
    byte[] outBytes = fs.ToArray();
    soapADFPoint = Encoding.UTF8.GetString(outBytes);
}

// Deserialize from SOAP.
byte[] inBytes = Encoding.UTF8.GetBytes(soapADFPoint);
System.IO.MemoryStream stream = new System.IO.MemoryStream(inBytes);
ESRI.ArcGIS.ADF.Web.Geometry.Point newSoapADFPoint = 
    (ESRI.ArcGIS.ADF.Web.Geometry.Point)soapFormatter.Deserialize(stream);

//=== Serialize to Binary using BinaryFormatter ===
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter binaryFormatter = new
    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
byte[] binaryADFPoint = null;
using(System.IO.MemoryStream memoryStreamIn = new System.IO.MemoryStream(8000))
{
    binaryFormatter.Serialize(memoryStreamIn, adfPoint);
    memoryStreamIn.Position = 0;
    binaryADFPoint = memoryStreamIn.ToArray();
}

// Deserialize from Binary.
ESRI.ArcGIS.ADF.Web.Geometry.Point newBinaryADFPoint = null;
using(System.IO.MemoryStream memoryStreamOut = new System.IO.MemoryStream(8000))
{
    memoryStreamOut.Write(binaryADFPoint, 0, binaryADFPoint.Length);
    memoryStreamOut.Seek(0, System.IO.SeekOrigin.Begin);
    newBinaryADFPoint = (ESRI.ArcGIS.ADF.Web.Geometry.Point)
        binaryFormatter.Deserialize(memoryStreamOut);
}