Inter-Process Communication with anonymous pipes, Part 02: transfer an object

In the first article of this series you have seen how to use anonymous pipes to transfer data between two processes. In the example application of this first article, only byte data was send between the processes. Within this article I want to show you a possibility to use more complex data.

 
Serialization

To transfer an object between the two processes I want to use the .NET serialization features. The idea is to serialize the data class into a string with XML format. Afterwards this string is send from parent to child process by using an anonymous pipe. The child will deserialize the received XML data and create the object instance of the data class.

 
Data object

To test the serialization feature I want to use the following data class. This data class has two string values and two lists with values. Furthermore I have added the ToString function which allows me to show the content of the data class within the demo console application.

public class MyClass
{
    public string MyValueA { get; set; }
    public string MyValueB { get; set; }
    public List<Int32> MyValuesC { get; set; }
    public List<string> MyValuesD { get; set; }

    public override string ToString()
    {
        StringBuilder data = new StringBuilder();

        data.Append("A = ");
        data.Append(MyValueA);
        data.Append(" | ");

        data.Append("B = ");
        data.Append(MyValueB);
        data.Append(" | ");

        data.Append("C = ");
        data.Append("[");
        if (MyValuesC != null)
        {
            foreach (int value in MyValuesC)
            {
                data.Append(value);
                data.Append(",");
            }
            data.Remove(data.Length - 1, 1);
        }
        data.Append("]");
        data.Append(" | ");

        data.Append("D = ");
        data.Append("[");
        if (MyValuesC != null)
        {
            foreach (string value in MyValuesD)
            {
                data.Append(value);
                data.Append(",");
            }
            data.Remove(data.Length - 1, 1);
        }
        data.Append("]");

        return data.ToString();
    }
}

 
Parent process

The parent process will send the data class to the child process. Therefore I have created a serialization function. This function is based on the XmlSerializer class and will convert the data object into a string with XML format.

public static string SerializeToXml(MyClass data)
{
    string xmlData = null;

    StringWriter stringWriter = null;

    XmlSerializer serializer = new XmlSerializer(data.GetType());
    stringWriter = new StringWriter();
    serializer.Serialize(stringWriter, data);

    xmlData = stringWriter.ToString();

    stringWriter.Close();

    return xmlData;
} 

 
The console application is based on the example of the previous article of this series. Only minor adaptations are done to create, serialize and show the data object.

static void Main(string[] args)
{
    //create streams
    var sender = new AnonymousPipeServerStream (PipeDirection.Out, HandleInheritability.Inheritable);
    var receiver = new AnonymousPipeServerStream (PipeDirection.In, HandleInheritability.Inheritable);
            
    //start client, pass pipe ids as command line parameter 
    string clientPath = @"...";
    string senderID = sender.GetClientHandleAsString();
    string receiverID = receiver.GetClientHandleAsString();

    var startInfo = new ProcessStartInfo (clientPath, senderID + " " + receiverID);
    startInfo.UseShellExecute = false;   
    Process clientProcess = Process.Start(startInfo);

    //release resources handlet by client
    sender.DisposeLocalCopyOfClientHandle();
    receiver.DisposeLocalCopyOfClientHandle();

    //create test data
    MyClass data = new MyClass();
    data.MyValueA = "foobar";
    data.MyValueB = null;
    data.MyValuesC = new List<Int32>() { 1, 2, 3 };
    data.MyValuesD = new List<string>() { "foo", "bar" };

    string xmlData = SerializeToXml(data);
            
    //write data
    Console.WriteLine("Parent send: " + data);
            
    using (StreamWriter writer = new StreamWriter(sender))
    {
        writer.WriteLine(xmlData);
        writer.Flush();                
    }            

    //read data
    int dataReceive = receiver.ReadByte();
    Console.WriteLine("Parent receive: " + dataReceive.ToString());

    //wait until client is closed
    clientProcess.WaitForExit();
    Console.WriteLine("Client execution finished");

    Console.ReadKey();
}

 
Child process

The child process will receive the XML data and convert it back into an object instance. Therefore I have implemented a deserialization function.

public static MyClass DeserializeFromXML(string xmlData)
{
    MyClass data = null;

    StringReader stringReader = null;

    XmlSerializer deserializer = new XmlSerializer(typeof(MyClass));
    stringReader = new StringReader(xmlData);
    data = (MyClass)deserializer.Deserialize(stringReader);
    stringReader.Close();

    return data;
}

 
Also the child application is nearly the same as in the first article of this series. Only the features to handle the data class where added.

static void Main(string[] args)
{
    string parentSenderID;
    string parentReceiverID;

    //get pipe handle id
    parentSenderID = args[0];
    parentReceiverID = args[1];
                        
    //create streams
    var receiver = new AnonymousPipeClientStream (PipeDirection.In, parentSenderID);
    var sender = new AnonymousPipeClientStream (PipeDirection.Out, parentReceiverID);

    //read data
    MyClass myClass;
    using (StreamReader reader = new StreamReader(receiver))
    {
        string line;
        string xmlData = "";
                
        while ((line = reader.ReadLine()) != null)
        {
            xmlData = xmlData + line;
        }
                                
        myClass = DeserializeFromXML(xmlData);
        Console.WriteLine("Client receive: " + myClass);
    }
                        
    //write data
    byte dataSend = 24;
    sender.WriteByte(dataSend);
    Console.WriteLine("Client send: " + dataSend.ToString());           
}

 
Summary

By using serialization features it is possible to transfer complex data objects over pipes. The combination of anonymous pipes and serialization will allow you to create a flexible and easy to use solution for data exchange between two processes.

Advertisements
Dieser Beitrag wurde unter .NET, C# abgelegt und mit , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Eine Antwort zu Inter-Process Communication with anonymous pipes, Part 02: transfer an object

  1. Pingback: Inter-Process Communication with named pipes, Part 01: transfer a byte stream | coders corner

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s