how to create a message from scracth?
-
Wednesday, February 07, 2007 10:04 PM
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
All Replies
-
Wednesday, February 14, 2007 4:57 AMYour 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 6:40 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.

