none
WCF - Read HTTP request body

    Question

  • I have MessageInspector (which derives from IDispatchMessageInspector) hooked in for my WCF REST service. I want to read the XML that I send in the request body?

    How can I do that?

    public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request , System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {

     

    //I want to read 'request' body.


    MP
    Thursday, April 15, 2010 8:00 PM

Answers

  • I see, so it seems like you're using the a REST/Raw mode in your service (the binary "junk" is the base64 encoding of your input). If this is the case, you can read the input as binary data, and reconstruct the message accordingly. See the code below for more information.

        public class Post_1d9d73d0_240c_46a8_853f_d7c3dfc85c6c
        {
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                string Process(Stream input);
            }
            public class Service : ITest
            {
                public string Process(Stream input)
                {
                    return new StreamReader(input).ReadToEnd();
                }
            }
            public class MyInspector : IDispatchMessageInspector, IEndpointBehavior
            {
                #region IDispatchMessageInspector Members

                public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
                {
                    XmlDictionaryReader bodyReader = request.GetReaderAtBodyContents();
                    byte[] input = bodyReader.ReadElementContentAsBase64();
                    Console.WriteLine("Incoming message: {0}", Encoding.UTF8.GetString(input));

                    //Now recreating the message
                    MemoryStream ms = new MemoryStream();
                    XmlDictionaryWriter w = XmlDictionaryWriter.CreateTextWriter(ms);
                    w.WriteStartElement("Binary");
                    w.WriteBase64(input, 0, input.Length);
                    w.WriteEndElement();
                    w.Flush();

                    // need to recreate the message, since it has already been read
                    ms.Position = 0;
                    Message newRequest = Message.CreateMessage(XmlReader.Create(ms), int.MaxValue, request.Version);
                    newRequest.Properties.CopyProperties(request.Properties);

                    request = newRequest;

                    return null;
                }

                public void BeforeSendReply(ref Message reply, object correlationState)
                {
                }

                #endregion

                #region IEndpointBehavior Members

                public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
                {
                }

                public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
                {
                }

                public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
                {
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
                }

                public void Validate(ServiceEndpoint endpoint)
                {
                }

                #endregion
            }
            static Binding GetBinding()
            {
                CustomBinding cb = new CustomBinding(new WebHttpBinding());
                cb.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new MyRawMapper();
                return cb;
            }
            class MyRawMapper : WebContentTypeMapper
            {
                public override WebContentFormat GetMessageFormatForContentType(string contentType)
                {
                    return WebContentFormat.Raw;
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
                endpoint.Behaviors.Add(new WebHttpBehavior());
                endpoint.Behaviors.Add(new MyInspector());
                host.Open();
                Console.WriteLine("Host opened");

                string body = "<Test><Parameters>" +
                    "<Parameter><Name>FirstName</Name><DataType>string</DataType><Value>Maulik</Value></Parameter>" +
                    "<Parameter><Name>LastName</Name><DataType>string</DataType><Value>Patel</Value></Parameter>" +
                    "</Parameters></Test>";
                Util.SendRequest(baseAddress + "/Process", "POST", "text/xml", body);

                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
        public static class Util
        {
            public static string SendRequest(string uri, string method, string contentType, string body)
            {
                string responseBody = null;

                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
                req.Method = method;
                if (!String.IsNullOrEmpty(contentType))
                {
                    req.ContentType = contentType;
                }
                if (!String.IsNullOrEmpty(body))
                {
                    byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
                    req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
                    req.GetRequestStream().Close();
                }

                HttpWebResponse resp;
                try
                {
                    resp = (HttpWebResponse)req.GetResponse();
                }
                catch (WebException e)
                {
                    resp = (HttpWebResponse)e.Response;
                }
                Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
                foreach (string headerName in resp.Headers.AllKeys)
                {
                    Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
                }
                Console.WriteLine();
                Stream respStream = resp.GetResponseStream();
                if (respStream != null)
                {
                    responseBody = new StreamReader(respStream).ReadToEnd();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine("HttpWebResponse.GetResponseStream returned null");
                }
                Console.WriteLine();
                Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
                Console.WriteLine();

                return responseBody;
            }
        }

    • Edited by Carlos Figueira Friday, April 16, 2010 6:21 PM code block not working
    • Proposed as answer by Carlos Figueira Thursday, April 22, 2010 5:23 AM
    • Marked as answer by Mog Liang Friday, April 23, 2010 9:08 AM
    Friday, April 16, 2010 6:20 PM

All replies

  • You can write the message out to a stream, and then you can read from that stream. Notice that after writing the message it cannot be consumed by the WCF runtime anymore, so you'll have to recreate it. The code below shows that.

        public class Post_1d9d73d0_240c_46a8_853f_d7c3dfc85c6c
        {
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                string Echo(string text);
            }
            public class Service : ITest
            {
                public string Echo(string text)
                {
                    return text;
                }
            }
            static Binding GetBinding()
            {
                BasicHttpBinding result = new BasicHttpBinding();
                return result;
            }
            public class MyInspector : IDispatchMessageInspector, IEndpointBehavior
            {
                #region IDispatchMessageInspector Members

                public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
                {
                    MemoryStream ms = new MemoryStream();
                    XmlDictionaryWriter w = XmlDictionaryWriter.CreateTextWriter(ms);
                    request.WriteMessage(w);
                    w.Flush();
                    Console.WriteLine("Incoming message: {0}", Encoding.UTF8.GetString(ms.ToArray()));

                    // need to recreate the message, since it has already been read
                    ms.Position = 0;
                    request = Message.CreateMessage(XmlReader.Create(ms), int.MaxValue, request.Version);

                    return null;
                }

                public void BeforeSendReply(ref Message reply, object correlationState)
                {
                }

                #endregion

                #region IEndpointBehavior Members

                public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
                {
                }

                public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
                {
                }

                public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
                {
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
                }

                public void Validate(ServiceEndpoint endpoint)
                {
                }

                #endregion
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                host.AddServiceEndpoint(typeof(ITest), GetBinding(), "").Behaviors.Add(new MyInspector());
                host.Open();
                Console.WriteLine("Host opened");

                ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(), new EndpointAddress(baseAddress));
                ITest proxy = factory.CreateChannel();

                using (OperationContextScope scope = new OperationContextScope((IContextChannel)proxy))
                {
                    //Changing a little the message
                    OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("MyHeader", "http://my.namespace", "some value"));
                    Console.WriteLine(proxy.Echo("Hello"));
                }

                ((IClientChannel)proxy).Close();
                factory.Close();

                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }

    • Edited by Carlos Figueira Thursday, April 15, 2010 8:47 PM code editor not working well
    Thursday, April 15, 2010 8:45 PM
  • I already tried this method. But all it gives me is some junk (binary) data.

    <Binary>PEVwaWNTVFM+PFBhcmFtZXRlcnM+PFBhcmFtZXRlcj48TmFtZT5GaXJzdE5hbWU8L05hbWU+PERhdGFUeXBlPnN0cmluZzwvRGF0YVR5cGU+PFZhbHVlPk1hdWxpazwvVmFsdWU+PC9QYXJhbWV0ZXI+PFBhcmFtZXRlcj48TmFtZT5MYXN0TmFtZTwvTmFtZT48RGF0YVR5cGU+c3RyaW5nPC9EYXRhVHlwZT48VmFsdWU+UGF0ZWw8L1ZhbHVlPjwvUGFyYW1ldGVyPjwvUGFyYW1ldGVycz48L0VwaWNTVFM+"

    While I am sending some XML data:

    <Test><Parameters><Parameter><Name>FirstName</Name><DataType>string</DataType><Value>Maulik</Value></Parameter><Parameter><Name>LastName</Name><DataType>string</DataType><Value>Patel</Value></Parameter></Parameters></Test>

     

     


    MP
    Friday, April 16, 2010 12:06 PM
  • I see, so it seems like you're using the a REST/Raw mode in your service (the binary "junk" is the base64 encoding of your input). If this is the case, you can read the input as binary data, and reconstruct the message accordingly. See the code below for more information.

        public class Post_1d9d73d0_240c_46a8_853f_d7c3dfc85c6c
        {
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                string Process(Stream input);
            }
            public class Service : ITest
            {
                public string Process(Stream input)
                {
                    return new StreamReader(input).ReadToEnd();
                }
            }
            public class MyInspector : IDispatchMessageInspector, IEndpointBehavior
            {
                #region IDispatchMessageInspector Members

                public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
                {
                    XmlDictionaryReader bodyReader = request.GetReaderAtBodyContents();
                    byte[] input = bodyReader.ReadElementContentAsBase64();
                    Console.WriteLine("Incoming message: {0}", Encoding.UTF8.GetString(input));

                    //Now recreating the message
                    MemoryStream ms = new MemoryStream();
                    XmlDictionaryWriter w = XmlDictionaryWriter.CreateTextWriter(ms);
                    w.WriteStartElement("Binary");
                    w.WriteBase64(input, 0, input.Length);
                    w.WriteEndElement();
                    w.Flush();

                    // need to recreate the message, since it has already been read
                    ms.Position = 0;
                    Message newRequest = Message.CreateMessage(XmlReader.Create(ms), int.MaxValue, request.Version);
                    newRequest.Properties.CopyProperties(request.Properties);

                    request = newRequest;

                    return null;
                }

                public void BeforeSendReply(ref Message reply, object correlationState)
                {
                }

                #endregion

                #region IEndpointBehavior Members

                public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
                {
                }

                public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
                {
                }

                public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
                {
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
                }

                public void Validate(ServiceEndpoint endpoint)
                {
                }

                #endregion
            }
            static Binding GetBinding()
            {
                CustomBinding cb = new CustomBinding(new WebHttpBinding());
                cb.Elements.Find<WebMessageEncodingBindingElement>().ContentTypeMapper = new MyRawMapper();
                return cb;
            }
            class MyRawMapper : WebContentTypeMapper
            {
                public override WebContentFormat GetMessageFormatForContentType(string contentType)
                {
                    return WebContentFormat.Raw;
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), GetBinding(), "");
                endpoint.Behaviors.Add(new WebHttpBehavior());
                endpoint.Behaviors.Add(new MyInspector());
                host.Open();
                Console.WriteLine("Host opened");

                string body = "<Test><Parameters>" +
                    "<Parameter><Name>FirstName</Name><DataType>string</DataType><Value>Maulik</Value></Parameter>" +
                    "<Parameter><Name>LastName</Name><DataType>string</DataType><Value>Patel</Value></Parameter>" +
                    "</Parameters></Test>";
                Util.SendRequest(baseAddress + "/Process", "POST", "text/xml", body);

                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
        public static class Util
        {
            public static string SendRequest(string uri, string method, string contentType, string body)
            {
                string responseBody = null;

                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(uri);
                req.Method = method;
                if (!String.IsNullOrEmpty(contentType))
                {
                    req.ContentType = contentType;
                }
                if (!String.IsNullOrEmpty(body))
                {
                    byte[] bodyBytes = Encoding.UTF8.GetBytes(body);
                    req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length);
                    req.GetRequestStream().Close();
                }

                HttpWebResponse resp;
                try
                {
                    resp = (HttpWebResponse)req.GetResponse();
                }
                catch (WebException e)
                {
                    resp = (HttpWebResponse)e.Response;
                }
                Console.WriteLine("HTTP/{0} {1} {2}", resp.ProtocolVersion, (int)resp.StatusCode, resp.StatusDescription);
                foreach (string headerName in resp.Headers.AllKeys)
                {
                    Console.WriteLine("{0}: {1}", headerName, resp.Headers[headerName]);
                }
                Console.WriteLine();
                Stream respStream = resp.GetResponseStream();
                if (respStream != null)
                {
                    responseBody = new StreamReader(respStream).ReadToEnd();
                    Console.WriteLine(responseBody);
                }
                else
                {
                    Console.WriteLine("HttpWebResponse.GetResponseStream returned null");
                }
                Console.WriteLine();
                Console.WriteLine("  *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*  ");
                Console.WriteLine();

                return responseBody;
            }
        }

    • Edited by Carlos Figueira Friday, April 16, 2010 6:21 PM code block not working
    • Proposed as answer by Carlos Figueira Thursday, April 22, 2010 5:23 AM
    • Marked as answer by Mog Liang Friday, April 23, 2010 9:08 AM
    Friday, April 16, 2010 6:20 PM