You have two different approaches for managing communication between the adapters and the integration server: messaging and remoting. Messaging communication is typically more reliable and fault tolerant, and remoting typically executes faster.
Chapter 4, "Applying Reliable Messaging," introduced the concept of real-time messaging and the Microsoft Message Queue (MSMQ) solution. You can use real-time messaging components to communicate messages between the integration adapters and the integration service with a series of messages. Because messages can contain any data that is understood by both sender and receiver, it serves as a reliable solution for exchanging the normalized XML data between applications. You also learned earlier that messages that are exchanged are kept in queues that protect messages from being lost. In general, messaging technologies offer tremendous benefits, including the following:
Integration adapters can use MSMQ to send messages and then continue processing regardless of whether the integration service is running or reachable over the network.
When networks become available or the integration services come back online, the messaging server will deliver any waiting messages.
MSMQ ensures that messages are not lost in transit, delivered out of order, or delivered more than once.
MSMQ can also route messages efficiently around failed machines and network bottlenecks, leaving administrators to configure redundant communications paths to ensure availability.
Communicating via messages does not require that components be aware of each other's implementation details. MSMQ services are used to only bridge components, not implement them.
To implement messaging as the communication mechanism for binding the adapter to the integration server, you will need to add a project reference to the messaging services to the adapter project. From Visual Studio .NET, select the adapter project within the Solution Explorer and choose Add ˜ Reference from its context menu. In the Add Reference dialog box, select the System.Messaging.dll component and add a code reference to the System.Messaging namespace. Next, add the SendToServer code to open a connection to a message queue and send the XML contents to the integration server (see Listing 12-18).
public string SendToServer( string strData ) { try { MessageQueue queue = new MessageQueue( "server\integrationQueue" ); queue.Send( "AppDemo", strData ); } catch( Exception x ) { EventLog systemLog = new EventLog(); systemLog.Source = "Integration Adapter"; systemLog.WriteEntry( x.Message, EventLogEntryType.Error, 0 ); systemLog.Dispose(); } finally { queue.Dispose(); } return strData; }
The SendToServer method connects to a message queue located on the server and sends a message that identifies the application within the message subject heading. The message body contains the application-specific XML created by the adapter.
Within the integration server, the message queue is checked for new incoming messages sent by the adapters. Listing 12-19 implements a method belonging to the integration server that monitors the message queue and processes incoming messages.
public void ProcessIncomingMessages() { do { try { MessageQueue queue = new MessageQueue( "server\integrationQueue" ); Message message = queue.Receive(new TimeSpan(0,0,3)); message.Formatter = new XmlMessageFormatter( new string[] {"System.String,mscorlib"} ); ProcessRequest( message.Body ); } catch( Exception x ) { EventLog systemLog = new EventLog(); systemLog.Source = "Integration Adapter"; systemLog.WriteEntry( x.Message, EventLogEntryType.Error, 0 ); systemLog.Dispose(); } finally { message.Dispose(); queue.Dispose(); } }while (true); return; }
As they arrive , the integration server passes the XML contained within the message body to the ProcessRequest method. The ProcessRequest method handles the application-to-application field mapping defined within a specified XSLT template.
Messaging services provide an excellent means of communication between adapters and the integration service. Another form of communication between these components is remoting . The .NET remoting services abstract client-server communication between .NET applications. Specific implementations support a fast binary protocol for real-time communication between client and server as well support for the Simple Object Access Protocol (SOAP) protocol over Hypertext Transfer Protocol (HTTP) for firewall-friendly communication across networks. Applying a remoting communication framework requires only a few steps: creating a common access assembly, implementing the server, and implementing the client.
The adapter code appears similar on the surface. Add a project reference to the System.Remoting namespace (see Listing 12-20).
public class DocumentAdapterService : System.ServiceProcess.ServiceBase, IIntegrationAdapter { private static HttpChannel _Channel = new HttpChannel(); private static string _IntegrationServerPath = "http://127.0.0.1:3200"; private static IIntegrationServer _IntegrationService; //... other collapsed service and IIntegrationAdapter code protected override void OnStart(string[] args) { try { LoadConfigurationData(); ChannelServices.RegisterChannel( _Channel ); _IntegrationService = (IIntegrationServer)Activator.GetObject( typeof( IIntegrationServer ), _IntegrationServerPath + "/IntegrationServer.soap" ); } catch( Exception x ) { EventLog systemLog = new EventLog(); systemLog.Source = "IssueTracker"; systemLog.WriteEntry(x.Message, EventLogEntryType.Error, 0); systemLog.Dispose(); } return; } }
Each integration adapter is a remoting client and a remoting server. Although the adapter needs to invoke methods belonging to the integration server, namely ProcessRequest, the server will also need to forward results by invoking adapter methods . Each adapter will need to be assigned a port address through which to communicate. If one computer is running multiple adapters, then each adapter will need to execute against a separate port number as set within the adapter configuration file.
When it comes to communication between the adapter and the integration server, only two methods are created: ProcessRequest and SendToAdapter. The ProcessRequest method is exposed to the integration adapters to receive incoming application-specific data. The SendToAdapter method exists to send outgoing data that has been mapped to a specific application format. The application constructor starts the remoting service and then waits to process requests . Listing 12-21 presents the modified IntegrationServer class definition.
public class IntegrationServer : System.ServiceProcess.ServiceBase, IIntegrationServer { private System.ComponentModel.Container components = null; static HttpChannel _Channel; static int _PortNumber = 3200; ArrayList _ApplicationMappings = new ArrayList(); protected override void OnStart(string[] args) { try { _Channel = new HttpChannel( _PortNumber ); ChannelServices.RegisterChannel( _Channel ); RemotingConfiguration.RegisterWellKnownServiceType( typeof( IntegrationServer ), "IntegrationServer.soap", WellKnownObjectMode.Singleton); } catch( Exception x ) { EventLog systemLog = new EventLog(); systemLog.Source = "Integration Adapter"; systemLog.WriteEntry(x.Message, EventLogEntryType.Error, 0); systemLog.Dispose(); } } protected override void OnStop() { } }
The IntegrationServer class is where the main integration work happens, when everything is implemented. The class begins with references to remoting framework and the existing IntegrationCommon assembly. The class declaration implements the MarshalByRefObject interface needed for remoting and the IIntegrationService interface needed by the adapters. Static class variables maintain the remoting- related values, and the Main method performs the work of registering a remoting service. First, a new HttpChannel object is created and initialized with a port number to which to listen. Next, that channel is registered and associated with the name IntegrationServer.soap . Finally, a ReadLine method keeps the application alive until the user presses the Enter key to shut down the application. The ProcessRequest, SendToAdapter, and LoadConfiguration methods appear in their skeletal forms.