first pass at adding required changes
diff --git a/src/ProtocolBuffers.Serialization/AbstractReader.cs b/src/ProtocolBuffers.Serialization/AbstractReader.cs
index f54c270..538af38 100644
--- a/src/ProtocolBuffers.Serialization/AbstractReader.cs
+++ b/src/ProtocolBuffers.Serialization/AbstractReader.cs
@@ -112,6 +112,16 @@
         /// Merges the input stream into the provided IBuilderLite 

         /// </summary>

         protected abstract bool ReadMessage(IBuilderLite builder, ExtensionRegistry registry);

+        

+        /// <summary>

+        /// Reads the root-message preamble specific to this formatter

+        /// </summary>

+        public abstract AbstractReader ReadStartMessage();

+

+        /// <summary>

+        /// Reads the root-message close specific to this formatter

+        /// </summary>

+        public abstract void ReadEndMessage();

 

         /// <summary>

         /// Merges the input stream into the provided IBuilderLite 

diff --git a/src/ProtocolBuffers.Serialization/AbstractWriter.cs b/src/ProtocolBuffers.Serialization/AbstractWriter.cs
index 6592c1d..50dfe67 100644
--- a/src/ProtocolBuffers.Serialization/AbstractWriter.cs
+++ b/src/ProtocolBuffers.Serialization/AbstractWriter.cs
@@ -44,6 +44,26 @@
         public abstract void WriteMessage(IMessageLite message);

 

         /// <summary>

+        /// Used to write any nessary root-message preamble. After this call you can call 

+        /// IMessageLite.MergeTo(...) and complete the message with a call to EndMessage().

+        /// These three calls are identical to just calling WriteMessage(message);

+        /// </summary>

+        /// <example>

+        /// AbstractWriter writer;

+        /// writer.StartMessage();

+        /// message.WriteTo(writer);

+        /// writer.EndMessage();

+        /// // ... or, but not both ...

+        /// writer.WriteMessage(message);

+        /// </example>

+        public abstract void StartMessage();

+

+        /// <summary>

+        /// Used to complete a root-message previously started with a call to StartMessage()

+        /// </summary>

+        public abstract void EndMessage();

+

+        /// <summary>

         /// Writes a Boolean value

         /// </summary>

         protected abstract void Write(string field, Boolean value);

diff --git a/src/ProtocolBuffers.Serialization/DictionaryReader.cs b/src/ProtocolBuffers.Serialization/DictionaryReader.cs
index cc5c680..f606bc9 100644
--- a/src/ProtocolBuffers.Serialization/DictionaryReader.cs
+++ b/src/ProtocolBuffers.Serialization/DictionaryReader.cs
@@ -23,6 +23,21 @@
         }

 

         /// <summary>

+        /// No-op

+        /// </summary>

+        public override AbstractReader ReadStartMessage()

+        {

+            return this;

+        }

+

+        /// <summary>

+        /// No-op

+        /// </summary>

+        public override void ReadEndMessage()

+        {

+        }

+

+        /// <summary>

         /// Merges the contents of stream into the provided message builder

         /// </summary>

         public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)

diff --git a/src/ProtocolBuffers.Serialization/DictionaryWriter.cs b/src/ProtocolBuffers.Serialization/DictionaryWriter.cs
index 96175a7..4c3b011 100644
--- a/src/ProtocolBuffers.Serialization/DictionaryWriter.cs
+++ b/src/ProtocolBuffers.Serialization/DictionaryWriter.cs
@@ -53,6 +53,19 @@
             message.WriteTo(this);

         }

 

+

+        /// <summary>

+        /// No-op

+        /// </summary>

+        public override void StartMessage()

+        { }

+

+        /// <summary>

+        /// No-op

+        /// </summary>

+        public override void EndMessage()

+        { }

+

         /// <summary>

         /// Writes a Boolean value

         /// </summary>

diff --git a/src/ProtocolBuffers.Serialization/Http/MessageFormatFactory.cs b/src/ProtocolBuffers.Serialization/Http/MessageFormatFactory.cs
new file mode 100644
index 0000000..7173d47
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/MessageFormatFactory.cs
@@ -0,0 +1,168 @@
+using System;

+using System.IO;

+using System.Xml;

+using System.Text;

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Extensions and helpers to abstract the reading/writing of messages by a client-specified content type.

+    /// </summary>

+    public static class MessageFormatFactory

+    {

+        /// <summary>

+        /// Constructs an ICodedInputStream from the input stream based on the contentType provided

+        /// </summary>

+        /// <param name="options">Options specific to reading this message and/or content type</param>

+        /// <param name="contentType">The mime type of the input stream content</param>

+        /// <param name="input">The stream to read the message from</param>

+        /// <returns>The ICodedInputStream that can be given to the IBuilder.MergeFrom(...) method</returns>

+        public static ICodedInputStream CreateInputStream(MessageFormatOptions options, string contentType, Stream input)

+        {

+            FormatType inputType = ContentTypeToFormat(contentType, options.DefaultContentType);

+

+            ICodedInputStream codedInput;

+            if (inputType == FormatType.ProtoBuffer)

+            {

+                codedInput = CodedInputStream.CreateInstance(input);

+            }

+            else if (inputType == FormatType.Json)

+            {

+                JsonFormatReader reader = JsonFormatReader.CreateInstance(input);

+                codedInput = reader.ReadStartMessage();

+            }

+            else if (inputType == FormatType.Xml)

+            {

+                XmlFormatReader reader = XmlFormatReader.CreateInstance(input);

+                reader.RootElementName = options.XmlReaderRootElementName;

+                reader.Options = options.XmlReaderOptions;

+                codedInput = reader.ReadStartMessage();

+            }

+            else

+                throw new NotSupportedException();

+

+            return codedInput;

+        }

+

+        /// <summary>

+        /// Merges the message from the input stream based on the contentType provided

+        /// </summary>

+        /// <typeparam name="TBuilder">A type derived from IBuilderLite</typeparam>

+        /// <param name="builder">An instance of a message builder</param>

+        /// <param name="options">Options specific to reading this message and/or content type</param>

+        /// <param name="contentType">The mime type of the input stream content</param>

+        /// <param name="input">The stream to read the message from</param>

+        /// <returns>The same builder instance that was supplied in the builder parameter</returns>

+        public static TBuilder MergeFrom<TBuilder>(this TBuilder builder, MessageFormatOptions options, string contentType, Stream input) where TBuilder : IBuilderLite

+        {

+            ICodedInputStream codedInput = CreateInputStream(options, contentType, input);

+            return (TBuilder)builder.WeakMergeFrom(codedInput, options.ExtensionRegistry);

+        }

+

+        /// <summary>

+        /// Writes the message instance to the stream using the content type provided

+        /// </summary>

+        /// <param name="message">An instance of a message</param>

+        /// <param name="options">Options specific to writing this message and/or content type</param>

+        /// <param name="contentType">The mime type of the content to be written</param>

+        /// <param name="output">The stream to write the message to</param>

+        public static void WriteTo(this IMessageLite message, MessageFormatOptions options, string contentType, Stream output)

+        {

+            FormatType outputType = ContentTypeToFormat(contentType, options.DefaultContentType);

+

+            ICodedOutputStream codedOutput;

+            if (outputType == FormatType.ProtoBuffer)

+            {

+                codedOutput = CodedOutputStream.CreateInstance(output);

+            }

+            else if (outputType == FormatType.Json)

+            {

+                JsonFormatWriter writer = JsonFormatWriter.CreateInstance(output);

+                if (options.FormattedOutput)

+                {

+                    writer.Formatted();

+                }

+                writer.StartMessage();

+                codedOutput = writer;

+            }

+            else if (outputType == FormatType.Xml)

+            {

+                XmlFormatWriter writer;

+                if (options.FormattedOutput)

+                {

+                    writer = XmlFormatWriter.CreateInstance(output);

+                }

+                else

+                {

+                    XmlWriterSettings settings = new XmlWriterSettings()

+                       {

+                           CheckCharacters = false,

+                           NewLineHandling = NewLineHandling.Entitize,

+                           OmitXmlDeclaration = true,

+                           Encoding = Encoding.UTF8,

+                           Indent = true,

+                           IndentChars = "  ",

+                           NewLineChars = Environment.NewLine,

+                       };

+                    writer = XmlFormatWriter.CreateInstance(XmlWriter.Create(output, settings));

+                }

+                writer.RootElementName = options.XmlWriterRootElementName;

+                writer.Options = options.XmlWriterOptions;

+                writer.StartMessage();

+                codedOutput = writer;

+            }

+            else

+                throw new NotSupportedException();

+

+            message.WriteTo(codedOutput);

+

+            if (codedOutput is AbstractWriter)

+                ((AbstractWriter) codedOutput).EndMessage();

+

+            codedOutput.Flush();

+        }

+

+

+        enum FormatType { ProtoBuffer, Json, Xml };

+

+        private static FormatType ContentTypeToFormat(string contentType, string defaultType)

+        {

+            switch ((contentType ?? String.Empty).Split(';')[0].Trim().ToLower())

+            {

+                case "application/json":

+                case "application/x-json":

+                case "application/x-javascript":

+                case "text/javascript":

+                case "text/x-javascript":

+                case "text/x-json":

+                case "text/json":

+                    {

+                        return FormatType.Json;

+                    }

+

+                case "text/xml":

+                case "application/xml":

+                    {

+                        return FormatType.Xml;

+                    }

+

+                case "application/binary":

+                case "application/x-protobuf":

+                case "application/vnd.google.protobuf":

+                    {

+                        return FormatType.ProtoBuffer;

+                    }

+

+                case "":

+                case null:

+                    if (!String.IsNullOrEmpty(defaultType))

+                    {

+                        return ContentTypeToFormat(defaultType, null);

+                    }

+                    break;

+            }

+

+            throw new ArgumentOutOfRangeException("contentType");

+        }

+    }

+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/Http/MessageFormatOptions.cs b/src/ProtocolBuffers.Serialization/Http/MessageFormatOptions.cs
new file mode 100644
index 0000000..5b88ac9
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/MessageFormatOptions.cs
@@ -0,0 +1,82 @@
+using System;

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Defines control information for the various formatting used with HTTP services

+    /// </summary>

+    public struct MessageFormatOptions

+    {

+        /// <summary>The mime type for xml content</summary>

+        /// <remarks>Other valid xml mime types include: application/binary, application/x-protobuf</remarks>

+        public const string ContentTypeProtoBuffer = "application/vnd.google.protobuf";

+

+        /// <summary>The mime type for xml content</summary>

+        /// <remarks>Other valid xml mime types include: text/xml</remarks>

+        public const string ContentTypeXml = "application/xml";

+        

+        /// <summary>The mime type for json content</summary>

+        /// <remarks>

+        /// Other valid json mime types include: application/json, application/x-json, 

+        /// application/x-javascript, text/javascript, text/x-javascript, text/x-json, text/json

+        /// </remarks>

+        public const string ContentTypeJson = "application/json";

+

+        private string _defaultContentType;

+        private string _xmlReaderRootElementName;

+        private string _xmlWriterRootElementName;

+        private ExtensionRegistry _extensionRegistry;

+

+        /// <summary>

+        /// The default content type to use if the input type is null or empty.  If this

+        /// value is not supplied an ArgumentOutOfRangeException exception will be raised.

+        /// </summary>

+        public string DefaultContentType

+        {

+            get { return _defaultContentType ?? String.Empty; }

+            set { _defaultContentType = value; }

+        }

+

+        /// <summary>

+        /// The extension registry to use when reading messages

+        /// </summary>

+        public ExtensionRegistry ExtensionRegistry

+        {

+            get { return _extensionRegistry ?? ExtensionRegistry.Empty; }

+            set { _extensionRegistry = value; }

+        }

+

+        /// <summary>

+        /// The name of the xml root element when reading messages

+        /// </summary>

+        public string XmlReaderRootElementName

+        {

+            get { return _xmlReaderRootElementName ?? XmlFormatReader.DefaultRootElementName; }

+            set { _xmlReaderRootElementName = value; }

+        }

+

+        /// <summary>

+        /// Xml reader options

+        /// </summary>

+        public XmlReaderOptions XmlReaderOptions { get; set; }

+

+        /// <summary>

+        /// True to use formatted output including new-lines and default indentation

+        /// </summary>

+        public bool FormattedOutput { get; set; }

+

+        /// <summary>

+        /// The name of the xml root element when writing messages

+        /// </summary>

+        public string XmlWriterRootElementName

+        {

+            get { return _xmlWriterRootElementName ?? XmlFormatWriter.DefaultRootElementName; }

+            set { _xmlWriterRootElementName = value; }

+        }

+

+        /// <summary>

+        /// Xml writer options

+        /// </summary>

+        public XmlWriterOptions XmlWriterOptions { get; set; }

+    }

+}
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/Http/ServiceExtensions.cs b/src/ProtocolBuffers.Serialization/Http/ServiceExtensions.cs
new file mode 100644
index 0000000..3ca9964
--- /dev/null
+++ b/src/ProtocolBuffers.Serialization/Http/ServiceExtensions.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;

+using System.Text;

+using Google.ProtocolBuffers;

+using System.IO;

+

+namespace Google.ProtocolBuffers.Serialization

+{

+    /// <summary>

+    /// Extensions for the IRpcServerStub

+    /// </summary>

+    public static class ServiceExtensions

+    {

+        /// <summary>

+        /// Used to implement a service endpoint on an HTTP server.  This works with services generated with the

+        /// service_generator_type option set to IRPCDISPATCH.

+        /// </summary>

+        /// <param name="stub">The service execution stub</param>

+        /// <param name="methodName">The name of the method being invoked</param>

+        /// <param name="options">optional arguments for the format reader/writer</param>

+        /// <param name="contentType">The mime type for the input stream</param>

+        /// <param name="input">The input stream</param>

+        /// <param name="responseType">The mime type for the output stream</param>

+        /// <param name="output">The output stream</param>

+        public static void HttpCallMethod(this IRpcServerStub stub, string methodName, MessageFormatOptions options, 

+            string contentType, Stream input, string responseType, Stream output)

+        {

+            ICodedInputStream codedInput = MessageFormatFactory.CreateInputStream(options, contentType, input);

+            IMessageLite response = stub.CallMethod(methodName, codedInput, options.ExtensionRegistry);

+            response.WriteTo(options, responseType, output);

+        }

+    }

+}

diff --git a/src/ProtocolBuffers.Serialization/JsonFormatReader.cs b/src/ProtocolBuffers.Serialization/JsonFormatReader.cs
index d4505d7..4033678 100644
--- a/src/ProtocolBuffers.Serialization/JsonFormatReader.cs
+++ b/src/ProtocolBuffers.Serialization/JsonFormatReader.cs
@@ -101,17 +101,34 @@
         }

 

         /// <summary>

-        /// Merges the contents of stream into the provided message builder

+        /// Reads the root-message preamble specific to this formatter

         /// </summary>

-        public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)

+        public override AbstractReader ReadStartMessage()

         {

             _input.Consume('{');

             _stopChar.Push('}');

 

             _state = ReaderState.BeginObject;

-            builder.WeakMergeFrom(this, registry);

-            _input.Consume((char) _stopChar.Pop());

+            return this;

+        }

+

+        /// <summary>

+        /// Reads the root-message close specific to this formatter

+        /// </summary>

+        public override void ReadEndMessage()

+        {

+            _input.Consume((char)_stopChar.Pop());

             _state = ReaderState.EndValue;

+        }

+

+        /// <summary>

+        /// Merges the contents of stream into the provided message builder

+        /// </summary>

+        public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)

+        {

+            AbstractReader rdr = ReadStartMessage();

+            builder.WeakMergeFrom(rdr, registry);

+            rdr.ReadEndMessage();

             return builder;

         }

 

diff --git a/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs b/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs
index d54507c..12d180d 100644
--- a/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs
+++ b/src/ProtocolBuffers.Serialization/JsonFormatWriter.cs
@@ -445,13 +445,31 @@
         /// </summary>

         public override void WriteMessage(IMessageLite message)

         {

+            StartMessage();

+            message.WriteTo(this);

+            EndMessage();

+        }

+

+        /// <summary>

+        /// Used to write the root-message preamble, in json this is the left-curly brace '{'.

+        /// After this call you can call IMessageLite.MergeTo(...) and complete the message with

+        /// a call to EndMessage().

+        /// </summary>

+        public override void StartMessage()

+        {

             if (_isArray)

             {

                 Seperator();

             }

             WriteToOutput("{");

             _counter.Add(0);

-            message.WriteTo(this);

+        }

+

+        /// <summary>

+        /// Used to complete a root-message previously started with a call to StartMessage()

+        /// </summary>

+        public override void EndMessage()

+        {

             _counter.RemoveAt(_counter.Count - 1);

             WriteLine("}");

             Flush();

diff --git a/src/ProtocolBuffers.Serialization/Properties/AssemblyInfo.cs b/src/ProtocolBuffers.Serialization/Properties/AssemblyInfo.cs
index fdae52b..b6581aa 100644
--- a/src/ProtocolBuffers.Serialization/Properties/AssemblyInfo.cs
+++ b/src/ProtocolBuffers.Serialization/Properties/AssemblyInfo.cs
@@ -65,12 +65,12 @@
 //

 // You can specify all the values or you can default the Build and Revision Numbers 

 // by using the '*' as shown below:

-// [assembly: AssemblyVersion("2.3.0.277")]

+// [assembly: AssemblyVersion("2.3.0.369")]

 

-[assembly: AssemblyVersion("2.3.0.277")]

+[assembly: AssemblyVersion("2.3.0.369")]

 #if !COMPACT_FRAMEWORK_35

 

-[assembly: AssemblyFileVersion("2.3.0.277")]

+[assembly: AssemblyFileVersion("2.3.0.369")]

 #endif

 

 [assembly: CLSCompliant(true)]
\ No newline at end of file
diff --git a/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj b/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj
index 0c53577..fdbbe50 100644
--- a/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj
+++ b/src/ProtocolBuffers.Serialization/ProtocolBuffers.Serialization.csproj
@@ -98,6 +98,9 @@
   </ItemGroup>

   <ItemGroup>

     <Compile Include="Extensions.cs" />

+    <Compile Include="Http\MessageFormatFactory.cs" />

+    <Compile Include="Http\MessageFormatOptions.cs" />

+    <Compile Include="Http\ServiceExtensions.cs" />

     <Compile Include="Properties\AssemblyInfo.cs" />

     <Compile Include="AbstractReader.cs" />

     <Compile Include="AbstractTextReader.cs" />

diff --git a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
index cb2cb2e..0d3bca6 100644
--- a/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
+++ b/src/ProtocolBuffers.Serialization/XmlFormatReader.cs
@@ -136,6 +136,41 @@
         }

 

         /// <summary>

+        /// Reads the root-message preamble specific to this formatter

+        /// </summary>

+        public override AbstractReader ReadStartMessage()

+        {

+            return ReadStartMessage(_rootElementName);

+        }

+

+        public AbstractReader ReadStartMessage(string element)

+        {

+            string field;

+            Assert(PeekNext(out field) && field == element);

+

+            XmlReader child = _input.ReadSubtree();

+            while (!child.IsStartElement() && child.Read())

+            {

+                continue;

+            }

+            child.Read();

+            return CloneWith(child);

+        }

+

+        /// <summary>

+        /// Reads the root-message close specific to this formatter, MUST be called

+        /// on the reader obtained from ReadStartMessage(string element).

+        /// </summary>

+        public override void ReadEndMessage()

+        {

+            Assert(0 == _input.Depth);

+            if(_input.NodeType == XmlNodeType.EndElement)

+            {

+                _input.Read();

+            }

+        }

+

+        /// <summary>

         /// Merge the provided builder as an element named <see cref="RootElementName"/> in the current context

         /// </summary>

         public override TBuilder Merge<TBuilder>(TBuilder builder, ExtensionRegistry registry)

diff --git a/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs b/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs
index fd36c1d..97fc6b2 100644
--- a/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs
+++ b/src/ProtocolBuffers.Serialization/XmlFormatWriter.cs
@@ -112,6 +112,43 @@
         }

 

         /// <summary>

+        /// Used to write the root-message preamble, in xml this is open element for RootElementName,

+        /// by default "&lt;root&gt;". After this call you can call IMessageLite.MergeTo(...) and 

+        /// complete the message with a call to EndMessage().

+        /// </summary>

+        public override void StartMessage()

+        {

+            StartMessage(_rootElementName);

+        }

+

+        /// <summary>

+        /// Used to write the root-message preamble, in xml this is open element for elementName. 

+        /// After this call you can call IMessageLite.MergeTo(...) and  complete the message with 

+        /// a call to EndMessage().

+        /// </summary>

+        public void StartMessage(string elementName)

+        {

+            if (TestOption(XmlWriterOptions.OutputJsonTypes))

+            {

+                _output.WriteStartElement("root"); // json requires this is the root-element

+                _output.WriteAttributeString("type", "object");

+            }

+            else

+            {

+                _output.WriteStartElement(elementName);

+            }

+        }

+

+        /// <summary>

+        /// Used to complete a root-message previously started with a call to StartMessage()

+        /// </summary>

+        public override void EndMessage()

+        {

+            _output.WriteEndElement();

+            _output.Flush();

+        }

+

+        /// <summary>

         /// Writes a message as an element using the name defined in <see cref="RootElementName"/>

         /// </summary>

         public override void WriteMessage(IMessageLite message)

@@ -124,19 +161,9 @@
         /// </summary>

         public void WriteMessage(string elementName, IMessageLite message)

         {

-            if (TestOption(XmlWriterOptions.OutputJsonTypes))

-            {

-                _output.WriteStartElement("root"); // json requires this is the root-element

-                _output.WriteAttributeString("type", "object");

-            }

-            else

-            {

-                _output.WriteStartElement(elementName);

-            }

-

+            StartMessage(elementName);

             message.WriteTo(this);

-            _output.WriteEndElement();

-            _output.Flush();

+            EndMessage();

         }

 

         /// <summary>