Click here to Skip to main content
15,884,023 members
Articles / Programming Languages / C#
Article

Marshalling For Remote Persistence

Rate me:
Please Sign up or sign in to vote.
4.64/5 (4 votes)
24 May 20073 min read 31.5K   181   20   6
An article on remote persistence implementation using .NET marshal by value and XML.

Introduction

The RemotingXml project was developed with two purposes in mind:

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

The RemotingXml project consists of a client and a server. The client creates and works with objects, and sends them to a server using the marshal-by-value technology to be stored in 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 three projects:

  • Server: contains the code for a remote server. The 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 the 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 the Serializable attribute or implements the ISerializable interface. In this example, the House and Address classes are used.

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

C#
[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:

C#
[Serializable]
[XmlInclude(typeof(House)), XmlInclude(typeof(Address))]
public class HouseList<T> : List<T>
{
}

This implementation is required for two purposes: an object passed to a remote server should be serializable; the object needs to provide the details of the 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:

C#
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 the _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, the role of which is to start the XmlHandler service.

C#
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

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

C#
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 the XmlHandler, and retrieves the objects from the XML files on the server:

C#
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

While 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 the 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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United Arab Emirates United Arab Emirates
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionclient Machine Pin
Zapss1-Jun-07 19:36
Zapss1-Jun-07 19:36 
AnswerRe: client Machine Pin
Tetyana Loskutova1-Jun-07 21:05
Tetyana Loskutova1-Jun-07 21:05 
It is surely possible to use the technology for access over the network. You will need to change the url on the client side:
url = @"http://212.101.201.110:65101/";
The actual access will depend on the network settings, because the port can be closed or blocked by the firewall.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.