Changing MessageEncoder in Interceptor

Last post 11-14-2009 4:34 AM by habibs. 4 replies.

Sort Posts:

  • Changing MessageEncoder in Interceptor

    11-03-2009, 7:34 AM
    • Member
      362 point Member
    • habibs
    • Member since 01-02-2003, 4:59 AM
    • Posts 79

    Hi, i have a Java mobile clients to my service. Some phones modify Content-Type of request by inserting text/plain before application/json; charset=utf-8. This causes exception on the server because wcf REST service treates incomming request as raw data and uses stream encoder. I need to replace this with JsonMessageEncoder , for this i wrote an interceptor and able to catch requests, but i am getting the following error:

    ---------------------------------------------------------------------------------------

    Error Status Code: 'InternalServerError'

    Details: Unable to deserialize XML body with root name 'Binary' and root namespace '' (for operation 'Login' and contract ('Auth', 'http://tempuri.org/')) using DataContractSerializer. Ensure that the type corresponding to the XML is added to the known types collection of the service.

    ---------------------------------------------------------------------------------------

     Here is my interceptor:

    public class MessageInterceptor : RequestInterceptor
        {
            public MessageInterceptor(): base(false)
            {
            }
    
            public override void ProcessRequest(ref RequestContext requestContext)
            {
                if (requestContext == null) return;
                Message request = requestContext.RequestMessage;
    
                if (request == null) return;
                var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
                
                string contentType = prop.Headers[HttpRequestHeader.ContentType];
                if (contentType != null)
                {
                    if (contentType.Contains("text/plain"))
                    {
                        prop.Headers[HttpRequestHeader.ContentType] = "application/json; charset=utf-8";
                        request.Properties[HttpRequestMessageProperty.Name] = prop;
                        request.Properties[WebBodyFormatMessageProperty.Name] = new WebBodyFormatMessageProperty(WebContentFormat.Json);
                        //var encoder = (MessageEncoder)request.Properties["Encoder"];
                        
                        request.Properties.Remove("Encoder");
    
                        var element = new WebMessageEncodingBindingElement();
                        var encFac = element.CreateMessageEncoderFactory();
                        
                        request.Properties.Add("Encoder",encFac.Encoder);
                    }
                }
            }
        }


  • Re: Changing MessageEncoder in Interceptor

    11-12-2009, 7:27 PM

    I understand what you are trying to do, and what you are doing wrong in the sample code.

    The fact that your message starts with <Binary> means that the wrong decoder is used.  I know you have tried to set the decoder by setting WebBodyFormatMessageProperty, but it did not work because by the time RequestInterceptor is run, the decoding already happened.

    To enable your scenario, you have to use a custom binding that allows you to specify which MIME type maps to which encoder.  Take a look at one such sample here: http://msdn.microsoft.com/en-us/library/bb943479.aspx.  It's not hard, so don't fret over this!

  • Re: Changing MessageEncoder in Interceptor

    11-13-2009, 4:47 PM
    • Member
      362 point Member
    • habibs
    • Member since 01-02-2003, 4:59 AM
    • Posts 79

    Hi Andrew, thanks for helping with this.  I have added a WebContentTypeMapper like below, but it is never called. I am still getting the same error:  "The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml', 'Json'. This can be because a WebContentTypeMapper has not been configured on the binding. See the documentation of WebContentTypeMapper for more details".


    class AppServiceHostFactory : ServiceHostFactory
      {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            WebServiceHost2 host =  new WebServiceHost2(serviceType, true, baseAddresses);
            //host.Interceptors.Add(new MessageInterceptor());
            host.Opened += new EventHandler(host_Opened);        
            return host;
        }
    
        void host_Opened(object sender, EventArgs e)
        {
            var host = (WebServiceHost2)sender;
            foreach (var ep in host.Description.Endpoints)
            {
                CustomBinding binding = new CustomBinding(ep.Binding);
                WebMessageEncodingBindingElement webMEBE = binding.Elements.Find<WebMessageEncodingBindingElement>();
                webMEBE.ContentTypeMapper = new JsonContentTypeMapper();
                ep.Binding = binding;
            }
        }
    
        public class JsonContentTypeMapper : WebContentTypeMapper
        {
            public override WebContentFormat GetMessageFormatForContentType(string contentType)
            {
                return WebContentFormat.Json;//return json content type always        }
        }    
      } 


    What might be the problem ?


    Thanks in advance.

  • Re: Changing MessageEncoder in Interceptor

    11-13-2009, 6:34 PM

    You might not be able to modify the binding after the service endpoint has been added.  The following worked for me, as I just tested.

            static void Main(string[] args)
            {
                var host = new WebServiceHost(typeof(MyService), new Uri("http://localhost/"));
                var binding = new CustomBinding(new WebHttpBinding());
                var encoder = binding.Elements.Find<WebMessageEncodingBindingElement>();
                encoder.ContentTypeMapper = new JsonContentTypeMapper();
                host.AddServiceEndpoint(typeof(MyService), binding, "http://localhost/MyService/");
                host.Open();
                Console.ReadKey();
            }
        }

        public class JsonContentTypeMapper : WebContentTypeMapper  
       {  
           public override WebContentFormat GetMessageFormatForContentType(string contentType)  
           {  
               return WebContentFormat.Json;//return json content type always       
           }  
        }      

        [ServiceContract]
        public class MyService
        {
            [WebGet]
            public string DoSomething()
            {
                return "hello";
            }
        }

     

  • Re: Changing MessageEncoder in Interceptor

    11-14-2009, 4:34 AM
    • Member
      362 point Member
    • habibs
    • Member since 01-02-2003, 4:59 AM
    • Posts 79

    I found solution for my problem. Here is it if someone else needs this:


    class AppServiceHostFactory : ServiceHostFactory
      {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            MyWebServiceHost host =  new MyWebServiceHost(serviceType, true, baseAddresses);
            return host;
        }    
      }
    
      public class JsonContentTypeMapper : WebContentTypeMapper
      {
          public override WebContentFormat GetMessageFormatForContentType(string contentType)
          {
              return WebContentFormat.Json;//always return json
          }
      }    
        
      public class MyWebServiceHost : WebServiceHost2
      {
          public MyWebServiceHost(object singletonInstance, params Uri[] baseAddresses)
              : base(singletonInstance, baseAddresses) { }
          
          public MyWebServiceHost(Type serviceType, bool dummy, params Uri[] baseAddresses)
              : base(serviceType, dummy, baseAddresses) { }
            
            protected override void OnOpening()
            {
                base.OnOpening();
                foreach (var ep in this.Description.Endpoints)
                {
                    CustomBinding binding = new CustomBinding(ep.Binding);
                    WebMessageEncodingBindingElement webMEBE = binding.Elements.Find<WebMessageEncodingBindingElement>();
                    webMEBE.ContentTypeMapper = new JsonContentTypeMapper();
                    ep.Binding = binding;
                }
            }
      }



    Andrew, thanks for helping with this.

Page 1 of 1 (5 items)