none
how to create a message from scracth?

    Question

  • Hello,

    I'm writing a MessageEncoder because I'm receiving a non-standard stream and I want to create a message from it's values, so:

    1) I 'understand' the parameters of the operation from the stream and use a DataContractSerializer to serialize them to the body of the message...

    The question is:

    How do I correctly write the body of the message??? Because I can write a parameter using the DCS but I can't write the Operation Name, so the dispatcher fails when it tries to resolve the call:

    OperationFormatter encountered an invalid Message body. Expected to find node type 'Element' with name '[OperationContract_Name]' and namespace '[ServiceContract_Namespace]'. Found node type 'Element' with name '[DataContract_Name]' and namespace '[DataContract_Namespace]'

    This is: I'm sending the parameter of the operation contract that I want to call, but I don't write the first element with the operation contract name...

    So, how can I do that???

     

    Thanks,

    M

     

     

     

     

    Wednesday, February 07, 2007 10:04 PM

Answers

  • If you want to know exactly what's the expected format of the body of the message, you can add an inspector to your service, call it from a WCF client, and see what the message looks like. The code below shows how it can be done for a simple service.

    [ServiceContract]
    public interface ITest1201739
    {
        [
    OperationContract]
        int Add(int x, int y);
    }
    public class Service1201739 : ITest1201739
    {
        public int Add(int x, int y) { return x + y; }
    }
    public class MyEndpointBehavior : IEndpointBehavior
    {
        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(
    new MyMessageInspector());
        }
        public void Validate(ServiceEndpoint endpoint) { }
    }
    public class MyMessageInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);
            Message temp = buffer.CreateMessage();
            Console.WriteLine("Message envelope: " + temp);
            XmlWriterSettings writerSettings = new XmlWriterSettings();
            writerSettings.Indent =
    true;
            writerSettings.IndentChars =
    " ";
            writerSettings.OmitXmlDeclaration =
    true;
            XmlWriter writer = XmlWriter.Create(Console.Out, writerSettings);
            Console.WriteLine("Message body:");
            writer.WriteNode(temp.GetReaderAtBodyContents(),
    true);
            writer.Flush();
            request = buffer.CreateMessage();
            return null;
        }
        public void BeforeSendReply(ref Message reply, object correlationState) { }
    }
    public class Test1201739
    {
        public static void Run()
        {
            ServiceHost host = new ServiceHost(typeof(Service1201739));
            string address = http://localhost:8000/Service1201739;
            BasicHttpBinding binding = new BasicHttpBinding();
            host.AddServiceEndpoint(typeof(ITest1201739), binding, address).Behaviors.Add(new MyEndpointBehavior());
            host.Open();
            ChannelFactory<ITest1201739> factory = new ChannelFactory<ITest1201739>(binding, new EndpointAddress(address));
            ITest1201739 proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Add(123, 456));
            ((
    IChannel)proxy).Close();
            factory.Close();
            host.Close();
        }
    }

    For this contract/binding, the expected format of the message body is the following ("http://tempuri.org" is the default namespace of the contract)

    <Add xmlns="http://tempuri.org/">
      <x>123</x>
      <y>456</y>
    </Add>

    As long as you follow the same format, the message should be accepted by the formatter.

    Wednesday, February 14, 2007 6:40 AM

All replies

  • Your best bet is probably find some auto-generated message and model from there.  We generally don't support handcrafted messages since anything could go wrong in there.  I am afraid no one here could answer your question with a simple paragraph...
    Wednesday, February 14, 2007 4:57 AM
  • If you want to know exactly what's the expected format of the body of the message, you can add an inspector to your service, call it from a WCF client, and see what the message looks like. The code below shows how it can be done for a simple service.

    [ServiceContract]
    public interface ITest1201739
    {
        [
    OperationContract]
        int Add(int x, int y);
    }
    public class Service1201739 : ITest1201739
    {
        public int Add(int x, int y) { return x + y; }
    }
    public class MyEndpointBehavior : IEndpointBehavior
    {
        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(
    new MyMessageInspector());
        }
        public void Validate(ServiceEndpoint endpoint) { }
    }
    public class MyMessageInspector : IDispatchMessageInspector
    {
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);
            Message temp = buffer.CreateMessage();
            Console.WriteLine("Message envelope: " + temp);
            XmlWriterSettings writerSettings = new XmlWriterSettings();
            writerSettings.Indent =
    true;
            writerSettings.IndentChars =
    " ";
            writerSettings.OmitXmlDeclaration =
    true;
            XmlWriter writer = XmlWriter.Create(Console.Out, writerSettings);
            Console.WriteLine("Message body:");
            writer.WriteNode(temp.GetReaderAtBodyContents(),
    true);
            writer.Flush();
            request = buffer.CreateMessage();
            return null;
        }
        public void BeforeSendReply(ref Message reply, object correlationState) { }
    }
    public class Test1201739
    {
        public static void Run()
        {
            ServiceHost host = new ServiceHost(typeof(Service1201739));
            string address = http://localhost:8000/Service1201739;
            BasicHttpBinding binding = new BasicHttpBinding();
            host.AddServiceEndpoint(typeof(ITest1201739), binding, address).Behaviors.Add(new MyEndpointBehavior());
            host.Open();
            ChannelFactory<ITest1201739> factory = new ChannelFactory<ITest1201739>(binding, new EndpointAddress(address));
            ITest1201739 proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Add(123, 456));
            ((
    IChannel)proxy).Close();
            factory.Close();
            host.Close();
        }
    }

    For this contract/binding, the expected format of the message body is the following ("http://tempuri.org" is the default namespace of the contract)

    <Add xmlns="http://tempuri.org/">
      <x>123</x>
      <y>456</y>
    </Add>

    As long as you follow the same format, the message should be accepted by the formatter.

    Wednesday, February 14, 2007 6:40 AM