Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

A quick way to Object Serialization


:P
On this page:

Serialization in .Net is one of the more useful features in .Net that I use all the time. Serialization – especially XML Serialization – makes it essentially trivial to write out the content of an object to a file, stream very easily. This is useful to pass data between applications, but also a great simple mechanism for saving and reloading state of applications. In fact, I use Serialization for just about every application to store a number of configuration settings easily.

 

Although Serialization is pretty straight forward, today I got tired of having to write the same serialization code over and over again. It's not much code, but remembering the stream and formatting options always required me looking this stuff up and fumbling for a few minutes in the docs or for an old sample.

 

Today, after having done this for the nth time, I added a couple of generic serialization methods to my utility class libraries. The result are the following two static methods:

 

using System;

using System.IO;

using System.Text;

using System.Xml;

using System.Xml.Serialization;

 

 

/// <summary>

/// Serializes an object instance to a file.

/// </summary>

/// <param name="Instance">the object instance to serialize</param>

/// <param name="Filename"></param>

/// <param name="BinarySerialization">determines whether XML serialization or binary serialization is used</param>

/// <returns></returns>

public static bool SerializeObject(object Instance, string Filename,

                                   bool BinarySerialization)

{

      bool retVal = true;

 

      if (!BinarySerialization)

      {

            XmlTextWriter writer = null;

            try

            {

                  XmlSerializer serializer =

                        new XmlSerializer(Instance.GetType());

 

                  // Create an XmlTextWriter using a FileStream.

                  Stream fs = new FileStream(Filename, FileMode.Create);

                  writer =    new XmlTextWriter(fs, new UTF8Encoding());

                  writer.Formatting = Formatting.Indented;

                  writer.IndentChar = ' ';

                  writer.Indentation = 3;

                       

                  // Serialize using the XmlTextWriter.

                  serializer.Serialize(writer,Instance);

            }

            catch(Exception)

            {

                  retVal = false;

            }

            finally

            {

                  if (writer != null)

                        writer.Close();

            }

      }

      else

      {

            Stream fs = null;

            try

            {

                  BinaryFormatter serializer = new BinaryFormatter();

                  fs = new FileStream(Filename, FileMode.Create);

                  serializer.Serialize(fs,Instance);

            }

            catch

            {

                  retVal = false;

            }

            finally

            {

                  if (fs != null)

                        fs.Close();

            }

      }

 

      return retVal;

}

 

/// <summary>

/// Deserializes an object from file and returns a reference.

/// </summary>

/// <param name="Filename">name of the file to serialize to</param>

/// <param name="ObjectType">The Type of the object. Use typeof(yourobject class)</param>

/// <param name="BinarySerialization">determines whether we use Xml or Binary serialization</param>

/// <returns>Instance of the deserialized object or null. Must be cast to your object type</returns>

public static object DeSerializeObject(string Filename,Type ObjectType,

                                       bool BinarySerialization)

{

      object Instance = null;

     

      if (!BinarySerialization)

      {

 

            XmlReader reader = null;

            XmlSerializer serializer = null;

            FileStream fs = null;

            try

            {

                  // Create an instance of the XmlSerializer specifying type and namespace.

                  serializer = new XmlSerializer(ObjectType);

 

                  // A FileStream is needed to read the XML document.

                  fs = new FileStream(Filename, FileMode.Open);

                  reader = new XmlTextReader(fs);

           

                  Instance = serializer.Deserialize(reader);

 

            }

            catch

            {

                  return null;

            }

            finally

            {

                  if (fs != null)

                        fs.Close();

 

                  if (reader != null)

                        reader.Close();

            }

      }

      else

      {

 

            BinaryFormatter serializer = null;

            FileStream fs = null;

 

            try

            {

                  serializer = new BinaryFormatter();

                  fs = new FileStream(Filename, FileMode.Open);

                  Instance = serializer.Deserialize(fs);

 

            }

            catch

            {

                  return null;

            }

            finally

            {

                  if (fs != null)

                        fs.Close();

            }

      }

 

      return Instance;

}

These methods work with file output for serialization since that is the most common scenario I run into as manual serialization usually ends up being a persistence mechanism. It's trivial to work with strings if you need to (see below)...

 

Both of these methods are static so they require that you pass in the type that you’re dealing with. My primary purpose originally was to serialize and deserialize my business objects, but it is impossible to deserialize an object into the this reference – you always must have variable to deserialize into.

 

The following example actually serialize an object you might use something like this:

 

wwUtils.SerializeObject(Configuration,"d:\\temp\\xConf.xml",false);

 

Then to reload the object:

 

Configuration = (ConfigClass) DeSerializeObject("d:\\temp\\xConf.xml",

                                                typeof(ConfigClass),false);

 

Much easier to deal with if you do this on a regular basis. If you need to return a deserialized object in string format you can cheat a little and dump the output to file and read it back in. This is not the most efficient way to do this (a MemoryStream would work better), but it requires very little work:

 

public string ToXml()

{

      wwUtils.SerializeObject(this,TFile,false);

      System.IO.StreamReader sr = new System.IO.StreamReader(TFile);

      string XML = sr.ReadToEnd();

      sr.Close();

 

      File.Delete(TFile);                                  

      return XML;

}

 

Remember that any objects that you want to serialize must be marked with the  [Serialiazable()] attribute or inherit from MarshalByRefObject. The object also may not contain any subobjects that may not serialize. For example, a DataRow cannot be serialized. IComponent.ISite cannot be serialized – if you have objects that include non-serializable subobjects serialization will fail. The workaround for this is to make those specific members of the class as non-serializable.

 

[XmlIgnore]   // DataRows can't serialize

public DataRow DataRow

{

      get { return this.oDataRow; }

      set { this.oDataRow = value; }

}

[NonSerialized]

DataRow oDataRow = null ;

 

You can use XMLIgnore on properties persisted into XML serialization. Note that this has no effect on binary serialization. For binary serialization use the [NonSerialized] attribute on field values, which causes field values not be persisted and passed forward.

 

Among other things serialization is a great way to persist data between application runs. I also find it invaluable to use for debugging as I can simply dump state of an object to disk at runtime and review later which can come in handy at times.

 

 


The Voices of Reason


 

Obuliraj
May 13, 2004

# re: A quick way to Object Serialization

Hi,
Im facing a problem in Serialization.
The problem is i have serailized an object in one machine and when i try to deserialize in other machine it throws the following exception.

"Exception Occurred: file name = C:\Program Files\Motorola\CTPU\CDMA\View Templates\Access Decode.mvt Wrong number of Members. Object System.Collections.Comparer has 1 members, number of members deserialized is 0."

When i install the program in some machine it works fine, but in some meachines it does not work fine.
Please help in finding a solution to this.
My Mail Id is obuli666@yahoo.com

Thanks & Regards,
obuliraj.

Rick Strahl
May 15, 2004

# re: A quick way to Object Serialization

Most likely the problem is one of permissions. If the file cannot be read the error you get is often not what you would expect, but serialization will fail anyway. Check permissions on the file or that the file is not locked by another application (or the same one). Always make sure you close your readers and writers when you're done with the data.

cindy
July 21, 2004

# re: A quick way to Object Serialization

I'm trying to serialize the System.Data.SqlClient.SqlCommand but not sucessful becaue SqlCommand has a Site member which implements ISite interface.

Do you know how to make this Site member non-serializable?

Thank you

Jack Detrick
September 01, 2004

# re: A quick way to Object Serialization

In VS2005(beta), BinaryFormatter serialize inserts an 8 char random name as the signature. In VS2003 it appears to be the project name. Now every time I recompile I can no longer deserialize any objects. Error "Unable to find Assembly __codexmjupjto" is an example. If I reserialize the objects, the problem disappears.

Just looking for a work around - Thanks in advance

Michael Erickson
October 28, 2004

# re: A quick way to Object Serialization

We have run into the exact same error, and found that it happens when you serialize an IComparable object on a system with .Net 1.1 sp1, and attempt to deserialize it on a system without the service pack.

It appears that sp1 is backwards compatible, and can deserialize earlier objects, but not the other way around.

Bharat Gadhia
November 09, 2004

# re: A quick way to Object Serialization

I have two asp.net web apps and I want to pass a user defined object from one app to another. I have serialised the object in one app(using SoapFormatter and memorystream object).
How to pass this object to another web app as object.I have written deserialisation method in another app where this object is expected.
Your help will be appricated.

Thank you.

Bharat Gadhia

Rick Strahl
November 09, 2004

# re: A quick way to Object Serialization

Bharat. Take a look at: http://west-wind.com/weblog/posts/481.aspx, which describes ways you can call other ASP.NET pages or applications. If it's truly another application you'll need to use HTTP and POST the serialized data to the other application or use a Web Service (which might be the better design choice).

Andreas Färnstrand
December 09, 2004

# re: A quick way to Object Serialization

Hi Rick!

I have a problem with serialization. I'm serializing an ArrayList with my own classes in it. When deserializing this in the same application everything works just fine. But when trying to deserialize it in another application it throws an invalidcastexception. I've tried everything. The classes in both applications are the same and still. It seems like since the assemblyinformation that's saved doesn't fit eachother, that it won't work.

What is wrong and how can I fix it?

Joe
May 09, 2005

# re: A quick way to Object Serialization

We are havging the exact same problem, as Andreas, has anyone solved this problem.

We are getting an ObjectType of <<filename>>_aspx+<<objectname>>

HELP!!!

tokyo_eye
May 23, 2005

# re: A quick way to Object Serialization

To Obuliraj:

I had the same problem with you.

"Object System.Collections.Comparer has 1 members, number of members deserialized is 0."

Please install .NET 1.1 SP1 on the machine of that developer. That will solve the issue.
( http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=3155 )

RR
November 25, 2005

# re: A quick way to Object Serialization

I'm having a strange issue with some serialization code that I have. When executing the following code within the context of a unit test where the assembly is not strongly named, it's successful. However, when running the same code from within the context of a Visual Studio Add-in (which talks to COM) and it IS strongly named at this point, it fails. The error I'm receiving is something to the effect of: "Cannot find the assembly blah, blah, blah." Now, the assembly is states it can't find, is the one I'm currently in when the exception is thrown. The line it's generating the exception on is the call to Deserialize. Any ideas?

public static Content SerializeCopy(Content content)
{
MemoryStream memoryStream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, content);
memoryStream.Seek(0, SeekOrigin.Begin);

return (Content)formatter.Deserialize(memoryStream);
}

fakethings
December 19, 2005

# re: A quick way to Object Serialization

I am having exactly the same problem as urs, anyone know the resolution? Please help

Simon Mc
May 15, 2006

# re: A quick way to Object Serialization

Hi, I am experiencing same problem too! The assembly is cannot find is the one I'm in.

Does anyone have a solution to this problem at all?


N
September 01, 2006

# re: A quick way to Object Serialization

Don't know if this has been answered elsewhere, but the assembly name (in your project properties) must be the same for the same for both projects in order to serialize in one project and de-serialize in the other.

Rick Strahl's Web Log
October 24, 2006

# Capturing Output from ASP.Net Pages - Rick Strahl's Web Log

Ever wonder how you can capture the content of the current ASP.Net page and either manipulate it or use it for things like Email confirmation or capturing for logging? How about executing other pages to perform mail merge type operations for things like confirmations and other notices that you may send to your customers via email? Or even providing text merging features in your WinForms applications? Here are a few tips on how you can accomplish these tasks with ASP.Net easily.

ivan
April 26, 2007

# re: A quick way to Object Serialization

I am having the same problem, when my dll is compiled as a COM dll.
"Unable to find assembly .... "

How can assembly not able to find itself???

I have something like the following.


[Serializable]
[ComVisible(true)]
class myClass
{
....
}

[ComVisible(true)]
class Wrapper
{
public void Wrap()
{
.... // this serializes ArrayList of instances of myClass
}
}

[ComVisible(true)]
class Unwrapper
{
public void Unwrap()
{
.... // this deserializes ArrayList of instances of myClass

}
}


------------------------------
so deserialization works fine when I call my dll from any .NET code, but when I call this dll as a COM dll from other application serialization works fine but during deserialization it tries to find itself and can't :(.

Same dll is used to serialize and deserialize myClass objects...

has anybody solved the problem.

Jim
November 14, 2007

# re: A quick way to Object Serialization

N is right on: make the assembly name the same for the program that serializes an object and the program that deserializes the object and the "Unable to find assembly..." exception goes away and everything works.

Many thanks!

Ninad Soman
June 16, 2008

# re: A quick way to Object Serialization

Hello,

I am getting the following error while trying to run a report. I am using SQL Server 2005.

w3wp!dataextension!5!6/12/2008-16:56:16:: w WARN: An exception has occurred trying to deserialize the field name. Details: System.ArgumentException: Invalid argument.
at Microsoft.AnalysisServices.AdomdClient.AdomdDataReader.GetOrdinal(String name)
at Microsoft.ReportingServices.DataExtensions.AdoMdDataReader.GetOrdinal(String fieldName)
w3wp!dataextension!5!6/12/2008-16:56:16:: w WARN: The field name '=Space(3*Fields!ParameterLevel.Value) + Fields!ParameterCaption.Value' is invalid.
w3wp!processing!5!6/12/2008-16:56:16:: e ERROR: Throwing Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: There is no data for the field at position 3., ;
Info: Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: There is no data for the field at position 3.

I am not able to get a resolution for this or what it refers to ......stuck up in there ...

Thoughts ?

Thanks for the help :)

abc
September 18, 2008

# re: A quick way to Object Serialization

http://msdn.microsoft.com/en-us/magazine/cc301761.aspx
resolves the problem defined "assembly not found" when deserializing.

jon
March 24, 2009

# re: A quick way to Object Serialization

if an object with unserializable nested objects cannot serialize and a DataRow cannot be serialized, then how can a DataTable and DataSet both be serialized?

Clem
January 29, 2010

# re: A quick way to Object Serialization

This is a nice simple example.
One comment...

On the web, serialization rarely uses an xml file stored on the server to serialize/deserialize objects. It is almost entirely done in memory.
It would be nice to have a simple example that serializes an object in memory from one aspx page and deserializes the object in another aspx page. (Basically serializing the object and deserializing after a postback).

In my mind, serializing using a file is the same as writing to a filestream. Serialization is not necessary. (but I'm new to this so I hope I am wrong).

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024