none
IXmlSerializable and Streaming through WCF

    Question

  • Hello,

    According to this article objects of type Stream, Message or IXMLSerializable can be streamed utilizing WCF.
    http://msdn.microsoft.com/en-us/library/ms789010.aspx

    I have successfully streamed an object of type Stream, but I have been unsuccessful in getting this to work for objects that implement IXMLSerializable. They are transferred but the server buffers them before they are sent.

    Is there a working example of a WCF implementation that streams IXMLSerializable objects?
    Friday, May 29, 2009 10:43 PM

Answers

  • Here you go... if you comment out the line which sets the transfer mode to Streamed, you'll see that the memory hike in that case is a lot larger than if that hadn't been set. Notice that even for streamed there is some memory increase, as even though the message is supposed to be "streamed", it's actually chunked in small buffers.

        public class Post_9146afa5_7703_412c_9435_a04af2c54fbf
        {
            public class MyIXS : IXmlSerializable
            {
                public System.Xml.Schema.XmlSchema GetSchema()
                {
                    return null;
                }
    
                public void ReadXml(XmlReader reader)
                {
                    long numberOfChars = 0;
                    Thread.Sleep(5000);
                    while (reader.Read())
                    {
                        numberOfChars += reader.Name.Length + reader.Value.Length;
                    }
                    Console.WriteLine("Read {0} characters", numberOfChars);
                    Console.WriteLine("After \"reading\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                }
    
                public void WriteXml(XmlWriter writer)
                {
                    writer.WriteStartElement("FirstName");
                    Console.WriteLine("Prior to \"writing\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                    for (int i = 0; i < 1000000; i++)
                    {
                        writer.WriteStartElement("Child");
                        writer.WriteString("Value " + i);
                        writer.WriteEndElement();
                    }
                    Console.WriteLine("Finished \"writing\", check service memory");
                    Console.WriteLine("After \"writing\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                    writer.WriteEndElement();
                }
            }
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                MyIXS GetIXS();
            }
            public class Service : ITest
            {
                public MyIXS GetIXS()
                {
                    return new MyIXS();
                }
            }
            static Binding GetBinding()
            {
                BasicHttpBinding result = new BasicHttpBinding();
                result.TransferMode = TransferMode.Streamed;
                result.MaxReceivedMessageSize = int.MaxValue;
                return result;
            }
    
            //static readonly string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            static readonly string baseAddress = "http://localhost:8000/Service";
    
            public static void TestService()
            {
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
                host.Open();
                Console.WriteLine("Host opened");
    
                Console.WriteLine("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
    
            public static void TestClient()
            {
                ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(), new EndpointAddress(baseAddress));
                ITest proxy = factory.CreateChannel();
    
                Console.WriteLine("Prior to \"reading\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                Console.WriteLine(proxy.GetIXS());
    
                ((IClientChannel)proxy).Close();
                factory.Close();
            }
            public static void Main(string[] args)
            {
                if (args[0] == "server")
                {
                    TestService();
                }
                else
                {
                    TestClient();
                }
            }
        }
    
    • Marked as answer by Marco Zhou Monday, June 01, 2009 7:30 AM
    Saturday, May 30, 2009 7:47 PM

All replies

  • Here you go... if you comment out the line which sets the transfer mode to Streamed, you'll see that the memory hike in that case is a lot larger than if that hadn't been set. Notice that even for streamed there is some memory increase, as even though the message is supposed to be "streamed", it's actually chunked in small buffers.

        public class Post_9146afa5_7703_412c_9435_a04af2c54fbf
        {
            public class MyIXS : IXmlSerializable
            {
                public System.Xml.Schema.XmlSchema GetSchema()
                {
                    return null;
                }
    
                public void ReadXml(XmlReader reader)
                {
                    long numberOfChars = 0;
                    Thread.Sleep(5000);
                    while (reader.Read())
                    {
                        numberOfChars += reader.Name.Length + reader.Value.Length;
                    }
                    Console.WriteLine("Read {0} characters", numberOfChars);
                    Console.WriteLine("After \"reading\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                }
    
                public void WriteXml(XmlWriter writer)
                {
                    writer.WriteStartElement("FirstName");
                    Console.WriteLine("Prior to \"writing\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                    for (int i = 0; i < 1000000; i++)
                    {
                        writer.WriteStartElement("Child");
                        writer.WriteString("Value " + i);
                        writer.WriteEndElement();
                    }
                    Console.WriteLine("Finished \"writing\", check service memory");
                    Console.WriteLine("After \"writing\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                    writer.WriteEndElement();
                }
            }
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                MyIXS GetIXS();
            }
            public class Service : ITest
            {
                public MyIXS GetIXS()
                {
                    return new MyIXS();
                }
            }
            static Binding GetBinding()
            {
                BasicHttpBinding result = new BasicHttpBinding();
                result.TransferMode = TransferMode.Streamed;
                result.MaxReceivedMessageSize = int.MaxValue;
                return result;
            }
    
            //static readonly string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            static readonly string baseAddress = "http://localhost:8000/Service";
    
            public static void TestService()
            {
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
                host.Open();
                Console.WriteLine("Host opened");
    
                Console.WriteLine("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
    
            public static void TestClient()
            {
                ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(), new EndpointAddress(baseAddress));
                ITest proxy = factory.CreateChannel();
    
                Console.WriteLine("Prior to \"reading\", memory size for this process: {0}", Process.GetCurrentProcess().PagedMemorySize64);
                Console.WriteLine(proxy.GetIXS());
    
                ((IClientChannel)proxy).Close();
                factory.Close();
            }
            public static void Main(string[] args)
            {
                if (args[0] == "server")
                {
                    TestService();
                }
                else
                {
                    TestClient();
                }
            }
        }
    
    • Marked as answer by Marco Zhou Monday, June 01, 2009 7:30 AM
    Saturday, May 30, 2009 7:47 PM
  • Thank you, this worked great.

    Monday, June 01, 2009 3:53 PM
  • What if XML should have the processing instruction like as below:

    1. <?

     

     

    xml version="1.0" encoding="UTF-8" standalone="yes"?>

    <FirstName>

    ....</FirstName>

    2. And also, If the response xml to have namespace prefix for the root tag ( for the children namespace was easy, i did that )

    like <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

    <a:FirstName xmlns:a = "MySpace" xmlns:b="YourSpace">

    <b:SomeChildElement>Value</b:SomeChildElement>

    ...</a:FirstElement>

    Please help,


    HydPhani
    Tuesday, March 08, 2011 2:35 PM
  • To put up custom root tag prefix, as I got solution by myself, pasting here, hope it helps somebody!

     

    XmlSerializer xmlSerializer = new XmlSerializer(rootTagClass.GetType(), defaultNamespace);

     

     

    MemoryStream stream = new MemoryStream();

     

     

    // writer settings for version, encoding, standalone attributes

     

     

    XmlWriterSettings settings = new XmlWriterSettings();

    settings.Encoding =

     

    Encoding.UTF8;

     

     

    // create the writer

     

     

    using (XmlWriter writer = XmlWriter.Create(stream, settings))

    {

     

     

    // write <?xml version="1.0" encoding="UTF-8" standalone="yes"?> tag to buffer with write settings

    writer.WriteStartDocument(

     

    true);

     

     

    // writer attach to serializer

    xmlSerializer.Serialize(writer, rootTagClass);

    }

     

     

    // set buffer pointer to intial position, to enable entire content flush

    stream.Position = 0;

     

     

    // Again load to Xmldocument to write root tag prefix

     

     

    XmlDocument xmlDoc = new XmlDocument();

    xmlDoc.Load(stream);

    xmlDoc.DocumentElement.Prefix = "MyPrefix"; // --> <MyPrefix:RootTag .... >...</>


    HydPhani
    Monday, August 01, 2011 2:53 PM