Archive for category Xml

Marshal By Value for Persistence

I was recently writing about how to use Marshal By Value with db4o and was very surprised how little information could I found on this actually simple subject.

So, to contribute to the global network – here is another Marshal By Value example, this time with xml.

Download RemotingXml.zip – 11.3 KB

Introduction

RemotingXml project was
developed with 2 purposes in mind:

  • show how to use marshal
    by value technology;
  • show how to implement a
    remote storage.

RemotingXml project consists
of a client and a server. The client creates and works with objects and sends them
to the server using marshal-by-value technology to be stored to XML files. The client
is also able to request the objects from the XML files.

This project might be helpful to those, who want to implement some kind of remote
persistence solution. In this example, XML files are used as a very simple and comprehensive
example, however the project can be easily used as a template to build a database
or file-based remoting storage solution.

Background

Though marshal-by-reference
remoting is widely covered on the net, marshal-by-value still tends to create some
confusion. This project is created to clear up this confusion and show an example
of how marshal-by-value objects can be used.

Solution Organization

RemotingXml consists of
3 projects:

  • Server: contains the code
    for a remote server. Server project is responsible for creating and starting remoting
    services.
  • Client: contains the code
    for creating persistent classes, sending them for serialization to the server and
    requesting the server for objects from the XML files.
  • PersistentClasses project
    is a library containing the definitions for classes used on the client and on the
    server. These include: class to be serialized, list wrapper for the serialized class
    and marshal-by-reference class used for persistent classes transport.

Persistent Classes

Persistent classes are the
classes that will be created on the client and serialized on the server. Any class
can be persisted if it either has Serializable attribute
or implements ISerializable interface. In this example,
House and Address classes are used.

Address class is saved as
a field in the House class:

[Serializable]
public class House
{
private Address _address;

private string _owner;
….
}

In order to save a list of houses we will need to create a special List implementation:

[Serializable]

[XmlInclude(typeof(House)), XmlInclude(typeof(Address))]

public class HouseList : List

{

}

This implementation is required for 2 purposes:
An object passed to a remote server should be serializable
The object need to provide the details of included classes for correct serialization.

Transport Class

In order to send the persistent
classes from the client to the server we will need a Marshal-By-Reference object:

    public class XmlHandler: MarshalByRefObject

    {

        private const string Extension = ".xml";

        // list of remote objects

        private IList _persistentObjects;        public IList PersistentObjects

        {

            get { return _persistentObjects; }

            set { _persistentObjects = value; }

        }

        // end PersistentObject

public void StoreData()

        {

            // Serialize object list to xml

            System.Console.WriteLine("persistentObjects " + _persistentObjects.Count);

            if (_persistentObjects.Count > 0)

            {

                // define the object type

                object persistentObject = _persistentObjects[0];

                XmlSerializer serializer = new XmlSerializer(_persistentObjects.GetType());

// delete the old file and create a new one

                string filename = persistentObject.GetType().Name + Extension;

                File.Delete(filename);

                StreamWriter xmlWriter = new StreamWriter(filename);

                // serialize object list

                serializer.Serialize(xmlWriter, _persistentObjects);

                xmlWriter.Close();

            }

        }

        // end StoreData

public IList RetrieveData(Type arrayType, Type objectType)

        {

            // Compose the file name

            string filename = objectType.Name + Extension;

            // deserialize

            XmlSerializer serializer = new XmlSerializer(arrayType);

            FileStream xmlFileStream = new FileStream(filename, FileMode.Open);

            IList objects = (IList)serializer.Deserialize(xmlFileStream);

            xmlFileStream.Close();

            return objects;

        }

        // end RetrieveData

    }

XmlHandler
holds a reference to the persistent objects array in _persistentObjects variable.
This variable is passed from the client.

As you can see there are methods for serializing and deselializing objects. These
methods are executed on the server.

Server

The Server project is presented
by a single XmlServer class, which role is to start XmlHandler service

    class XmlServer

    {

        static void Main(string[] args)

        {

            // Setting up http channel

            HttpChannel channel = new HttpChannel(65101);

            ChannelServices.RegisterChannel(channel);            Type XmlHandler = Type.GetType("RemotingXml.PersistentClasses.XmlHandler, PersistentClasses");

            RemotingConfiguration.RegisterWellKnownServiceType(

                    XmlHandler,

                    "XmlHandlerEndPoint",

                    WellKnownObjectMode.Singleton

                );

            Console.WriteLine("XmlHandler is ready.");

// Keep the server running until the user presses

            // the Enter key.

            Console.WriteLine("Services are running. Press Enter to end...");

            Console.ReadLine();

        }

        // end Main

    }

Client

Client project contains Program class.
In the constructor a connection to the XmlHandler service is established:

        public Program()

        {

            string url;            // Setup a client channel to our services.

            HttpChannel channel = new HttpChannel(0);

            url = @"http://LocalHost:65101/";

// Register the channel

            ChannelServices.RegisterChannel(channel, false);

// Set an access to the remote proxy

            xmlHandler = (XmlHandler)RemotingServices.Connect(

                typeof(PersistentClasses.XmlHandler), url + "XmlHandlerEndPoint"

                );

        }

        // end Program

The RunTest method creates
a list of House objects, sends them to the server using XmlHandler and retrieves
the objects from the XML files on the server:

        private void RunTest()

        {

            // an object to be stored remotely

            House house = new House(new Address("East London", "266 Oxford Street"), "Derick Hopkins");

            // Create a list to hold House instances

            HouseList persistentObjects = new HouseList();

            persistentObjects.Add(house);

            // another House for a list

            house = new House(new Address("East London", "23 Stewart Drive"), "Om Henderson");

            persistentObjects.Add(house);

            // Pass House list to the server using XmlHandler

            xmlHandler.PersistentObjects = (IList)persistentObjects;

            // Call method on the server to store houses to an XML file

            xmlHandler.StoreData();

            // Test what is stored to the database

            IList result = xmlHandler.RetrieveData(typeof(HouseList), typeof(House));

            foreach (object obj in result)

            {

                System.Console.WriteLine(obj);

            }

        }

        // end RunTest

Points of Interest

Creating this project I
had an idea in mind to make it completely generic by using generics for persistent
object collections. However, the idea was not realized due to the fact that Soap
serializer does not support generics and explicit using of binary serializers on
the client and the server still does not solve the problem.

History

2007-05-25 First version.

Advertisements

Leave a comment