Mark Wilson I am the creator of TopXML. I am available for international and local (Australia) contracts. I am a Solution Architect/Business Analyst. I have worked in IT in several countries (NZ, Australia, South Africa, UK) building and training teams for government and very large non-governmental organizations. I am ex-Microsoft Consulting Services. I wrote the first book on Microsoft XML published in 2000 called XML Programming with VB and ASP. Most recently I have been building tools for the SEO industry. Ask me for a 37 point SEO health-checkup for your website.
First posted :
03/24/2008
Times viewed :
258
Sending RPC Responses
In .NET, like in many other environments, methods can return
results either as a return value or through specially marked method parameters.
Calling methods through SOAP should be no different, right? Even though we
invoke a method on a different server, we still want the method results back.
That is why the SOAP standard in section 7 defines the format for returning
results from an RPC call:
The results
are embedded into the message body.
The first
child element of the body is by convention named after the invoked method with
the word “Response” appended.
The first
child element of the result represents the return value. A certain name is also
not required for this element, but by convention it usually is the name of the
method with the word “Result” appended.
Any
outbound parameters ([in,out]
and [out])
follow the return value with their original names and in the same order they
appeared in the original message.
From this format description we can gather that a response
message looks very similar to a request message, the difference is mostly in
the semantics. Because the .NET Framework offers no special support for
response messages we have to produce them the same way we generate the request
messages: We serialize an object that implements the ISoapMessage interface. There is no
special support in the .NET Framework to generate response messages because the
responses are too specific to the invoked method to come up with a Framework
class that can provide more value than SoapMessage.
Now that we know in which format we have to marshal the results
back to the caller we can write some code to add this functionality to our SoapRPCMessageReceiver
class. First we need the stub class to return the results from the method
invocation. The most extensible way is to setup the complete response message
inside the DispatchMessage()
method. Thus we avoid tailoring the signature of DispatchMessage() to a specific
method and can easily process all methods the RPC server exposes within the
same DispatchMessage()
method. In the example here, we take the return value from InsertNewUser(),
store it in the ParamValues
array of a SoapMessage
object. We also set the MethodName
and ParamNames
properties according to the recommended conventions. Then the SoapRPCMessageReceiver
can return the SoapMessage
via ProcessSoapStream()
to the Receive()
method, which can send the response back to the original sender.
Listing Setting up a response message
public SoapMessage
DispatchMessage( SoapMessage msg )
The Receive()
method of the SoapRPCMessageReceiver
is the best place to send the response, because it already has the necessary
information where to send it to. Figuring out where to send a response to is a
little bit trickier with message queues than it is with a
request<->response oriented transport protocol like HTTP for example. An
HTTP server always returns the response on the same connection it received the
request. With message queues it is not so obvious who will receive the response
because there is no persistent connection between the sender and the receiver
once the message is delivered. For the receiver to determine where the response
goes it needs a little cooperation from the sender, which has to supply the
path to a response queue with the request Message (the System.Messaging.Message, not the
SOAP message). The receiver then can access the response queue through the ResponseQueue
property of the Message
object.
To complete the example in this section let’s extend the Receive() method
to send the response message to the ReponseQueue. We can re-use the SoapRPCMessageSender
class we created in the listing to do the sending. Receive() only needs to check for a
response queue and send the SoapMessage
returned from ProcessSoapStream().
Listing 14.9 shows the complete implementation of the Receive() method. Now we are only one
step away from a functional SOAP RPC server. The next section will show us how
to send response messages with the return values, but also how to communicate
exceptions we encountered while we processed a SOAP message.
Listing Sending response messages to the ResponseQueue
public new SoapMessage
ProcessSoapStream( Stream stream )
{
SoapMessage msg = new SoapMessage();
_Formatter.TopObject =
msg;
_Formatter.Deserialize(
stream );
return _Stub.DispatchMessage( msg );
} // ProcessSoapStream()
public void Receive ( int timeout )
{
Message queueMessage;
try
{
queueMessage =
_ReceivingQueue.Receive(
new TimeSpan( 0, 0,
0, timeout, 0 ) );
Console.WriteLine(
"Message received." );
SoapMessage
responseMsg =
ProcessSoapStream(
queueMessage.BodyStream );
if( ( null != queueMessage.ResponseQueue )
&& ( null !=
responseMsg ) )
{
SoapRPCMessageSender sender =
new SoapRPCMessageSender(queueMessage.ResponseQueue.Path);