TCP Messaging


WSE provides so many different features that it would be impossible to provide adequate coverage of them in a single chapter. Instead, this chapter will cover some of the more interesting features of WSE.

NOTE

If you want more information about the aspects of WSE that this chapter doesn't cover, you can always read up on WSE using MSDN at the Web Services Developer Center: msdn.microsoft.com/webservices/building/wse/default.aspx.


If you have been reading this book in order, you've already read the chapter introducing you to the basic concepts of web services. Although web services and the ability to send SOAP messages over HTTP might be empowering to quite a few applications, it doesn't do any good to those applications that aren't running on machines with an IIS web server. The next section will show you how some of the classes provided by WSE 2.0 can facilitate SOAP messaging over TCP where neither endpoint needs to have IIS installed.

SOAP over TCP

Web services operate by sending SOAP messages between the client and the server over HTTP. This is great if what you are doing is writing an application that is designed to sit on a web server running IIS. However, what if you want to create a situation that lends itself more to a peer-to-peer architecture? How do you send messages between two different applications that are able to communicate via TCP/IP, but aren't necessarily on machines that have web servers?

Without using WSE, there are a few options. You can use Remoting, but Remoting is a very RPC-like model, and becomes overly complex if all you are trying to do is exchange messages rather than remotely invoke methods. You could also write your own socket code. If you have a lot of experience with socket code, this might be a good alternative. However, in most situations, you don't have time to write your own low-level socket communication library.

Thankfully, WSE now provides the ability to send and receive SOAP messages on several levels. You can write code designed to read and write raw SOAP messages over TCP, or you can write code that works at a slightly higher level using the concepts of a service and a client. The four classes that make this possible are SoapSender, SoapReceiver, SoapService, and SoapClient.

One of the really important and powerful features of WSE 2.0 is that you can use the SOAP classes to send and receive SOAP messages on any of three different protocols: in-process (for communicating between two running applications on the same machine), TCP, and HTTP.

SoapSender and SoapReceiver

SoapSender and SoapReceiver are two classes that facilitate SOAP message transmission over any of the supported network protocols, such as HTTP, TCP, or the in-process memory protocol. Before you can start using these classes to their utmost, you need to make sure that you have switched to the mindset of messaging rather than remote procedure calls (RPCs). Because the messages are created and sent on the fly, the network connection between endpoints could actually go down between transmissions. As long as there is a network connection available at the time of message transmission, the message will be sent properly.

Another twist in thinking about message transmission is that either endpoint can be a sender or a receiver. The traditional concepts of client and server do not apply when dealing purely with senders and receivers.

To illustrate how SoapSender and SoapReceiver work, examine two sample applications. The first application is a Windows Forms application that listens on the soap.tcp protocol for SOAP messages. The second is a Console application that allows the user to send messages to the Windows Forms application. Although the applications themselves are fairly simple, powerful networking applications can be created with some of the features of WSE 2.0.

The first step to creating an application that can receive messages is to create a class that derives from SoapReceiver. Listing 33.1 shows the MessageReceiver class, part of the SoapMessageReceiver WinForms application.

Listing 33.1. The MessageReceiver Class Derives from SoapReceiver
 using System; using Microsoft.Web.Services2.Messaging; using Microsoft.Web.Services2; namespace SoapMessageReceiver {   /// <summary>   /// Summary description for MessageReceiver.   /// </summary>   public class MessageReceiver : SoapReceiver   {     public delegate void MessageReceivedDelegate(string message);     public event MessageReceivedDelegate MessageReceived;     protected override void Receive(SoapEnvelope envelope)     {       System.Diagnostics.Debug.WriteLine("Received a Message.");       string message = envelope.SelectSingleNode("//msg").InnerText;       System.Diagnostics.Debug.WriteLine("Message Received: " + message);       if (MessageReceived != null)         MessageReceived(message);     }   } } 

For the .NET Framework to know which class to call when a message is sent to a specific URI, that class instance must be registered. The following lines from the main form take care of registering the SoapReceiver:

 Uri receiverUri = new Uri("soap.tcp://localhost/messages"); rcv = new MessageReceiver(); rcv.MessageReceived +=   new SoapMessageReceiver.MessageReceiver.MessageReceivedDelegate(rcv_MessageReceived); SoapReceivers.Add(receiverUri, rcv); 

The SoapReceiver class has one method, Receive, that takes a SoapEnvelope argument. The class shown previously extracts the information from the custom message that is created (an XML node called msg) and then fires another event, allowing the main GUI thread to respond to the new information. The main form simply handles the event and displays the information in a text box.

Next in the application construction process is the creation of code that sends the SOAP envelope to the receiver. For this sample, the code is in a Console application that creates a custom SOAP envelope and sends it to the listener. Listing 33.2 shows the code from the Console application that creates the custom SOAP envelope and sends it on the soap.tcp protocol .

Listing 33.2. SOAP Message Sender
 using System; using Microsoft.Web.Services2; using Microsoft.Web.Services2.Messaging; namespace SoapMessageSender {   /// <summary>   /// Summary description for Class1.   /// </summary>   class Class1   {     /// <summary>     /// The main entry point for the application.     /// </summary>     [STAThread]     static void Main(string[] args)     {       Uri destUri = new Uri("soap.tcp://localhost/messages");       string msg = "-";       while (msg.Length > 0)       {         Console.Write("Enter message to send (blank to quit): ");         msg = Console.ReadLine();         if (msg != string.Empty) {           SoapEnvelope env = CreateTextMessage( msg );            env.Context.Addressing.Action =             new Microsoft.Web.Services2.Addressing.Action("urn:messages:send");           SoapSender sender = new SoapSender( destUri );           sender.Send( env );         }       }     }     static SoapEnvelope CreateTextMessage(string msg)     {       SoapEnvelope e = new SoapEnvelope();       e.CreateBody();       e.Body.InnerXml = "<msg>" + msg + "</msg>";       return e;     }   } } 

To test this application, first run the Windows Forms listener application. Because the SoapReceiver has been registered with the SoapReceivers collection, it will have its Receive method invoked and the transmitted SOAP envelope passed.

With the Windows Forms application running, launch the Console application and start typing in messages. You should notice that the text area in the Windows Forms application has been receiving the messages, as shown in Figure 33.1.

Figure 33.1. A Windows Forms application listening for soap.tcp messages.


The SoapService Class

Using the SoapSender and SoapReceiver classes, you can implement some incredibly powerful network messaging for your applications. But implementing the SOAP envelope yourself, including all the logic to build and parse the SOAP body, can become tedious and introduce additional potential points of failure in your application.

A higher level set of messaging classes is available to reduce the complexity and make it even easier to use SOAP over TCP or HTTP in a pure messaging environment: SoapService and SoapClient. When dealing with SoapSender and SoapReceiver, you have to write all the code that differentiates between the actions you want performed. For example, if you have three different methods you want to invoke from a client, you have to code the convention used to distinguish which method you want to invoke, and the service must be coded so that it recognizes that convention. Thankfully, Microsoft has provided the SoapService and SoapClient classes that automatically have support for determining which methods to invoke remotely.

The first step to implementing TCP/SOAP messaging using a SoapService is to create a class that derives from SoapService. Instead of overriding the default Receive method, individual methods can be created so long as they are marked with the SoapMethod attribute. Listing 33.3 shows a class that inherits from SoapService. Like the previous class, this one exposes a method that allows a WinForms GUI to listen for incoming messages.

Listing 33.3. The MessageService Class Inherits from SoapService
 using System; using Microsoft.Web.Services2; using Microsoft.Web.Services2.Messaging; using Microsoft.Web.Services2.Addressing; namespace SoapServiceWin {   /// <summary>   /// Summary description for MessageService.   /// </summary>   public class MessageService : SoapService   {     public delegate void MessageReceivedDelegate(string message);     public event MessageReceivedDelegate OnMessageReceived;     [SoapMethod("ReceiveMessage")]     public SoapEnvelope ReceiveMessage(SoapEnvelope env)     {       System.Diagnostics.Debug.WriteLine("Received message");       string message = "test";       try       {         message = env.Body.InnerText;       }       catch (Exception ex)       {         message = "Failed to find body: " + ex.ToString();       }       if (OnMessageReceived != null)         OnMessageReceived(message);       return new SoapEnvelope();     }   } } 

In the preceding code, there is a single method marked with the SoapMethod attribute. The string argument to that attribute must match the name of the method that a SoapClient invokes in order for a client and service to communicate. If results need to be sent back to the client, those results can be enclosed in a SOAP envelope. The preceding ReceiveMessage method takes a message contained in the raw SOAP body and passed it to the Windows Forms GUI via events. The code to register the SoapService looks virtually identical to the code to register a SoapReceiver and is located in the main form's constructor:

 ms = new MessageService(); ms.OnMessageReceived +=   new SoapServiceWin.MessageService.MessageReceivedDelegate(     ms_OnMessageReceived); Uri localUri = new Uri("soap.tcp://localhost/MessageService"); EndpointReference epr = new EndpointReference(localUri); SoapReceivers.Add(epr, ms); 

The SoapClient Class

To communicate with a SoapService, you need a SoapClient. The SoapClient, which inherits from SoapSender, abstracts the busywork of identifying the name of the method to execute on the remote server. Listing 33.4 shows a class that derives from SoapClient that can send requests to execute the ReceiveMessage remotely via the soap.tcp WSE protocol.

Listing 33.4. The MessagingSoapClient Class Derives from SoapClient
 using System; using Microsoft.Web.Services2; using Microsoft.Web.Services2.Messaging; using Microsoft.Web.Services2.Addressing; namespace SoapClientApp {   /// <summary>   /// Summary description for SoapClient.   /// </summary>   public class MessagingSoapClient : SoapClient   {     public MessagingSoapClient(       EndpointReference destination ) : base(destination) { }     [SoapMethod("ReceiveMessage")]     public void SendReceiveMessage(SoapEnvelope env)     {       base.SendRequestResponse("ReceiveMessage", env );     }   } } 

There are two different ways that you can send a message to a SoapService: SendRequestResponse and SendOneWay. The first method, used in the preceding code, expects that the service will supply a populated SOAP envelope as a response. The second method is a fire-and-forget style method: issue the call and it will be asynchronously invoked without expecting a value in return. The following code prompts a user at the console for a message to send to the Windows Forms service host:

 Uri destination = new Uri("soap.tcp://localhost/MessageService"); EndpointReference epr = new EndpointReference( destination ); MessagingSoapClient msc = new MessagingSoapClient( epr ); Console.Write("Type message to send below:"); string message = Console.ReadLine(); SoapEnvelope env = new SoapEnvelope(); env.SetBodyObject(message); msc.SendReceiveMessage( env ); 

With the Windows Forms application running and actively listening for those messages, the server application looks as shown in Figure 33.2.

Figure 33.2. The GUI host for the MessageService class.




    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net