http://www.developer.com/services/article.php/3616711/A-Windows-Service-Solution-for-Unreliable-Web-Services.htm
Using the Internet to solve integration problems can be an adventure. If you've experimented with Internet Web services integration, you know reliability is a big issue. The source of the problem can be anywhere between your potentially unreliable Internet connection and the hosting vendor's possibly overloaded server. You can make network- and Internet-access improvements on your end, but what do you do to fix the vendor's part of the problem? This article explains an approach for addressing Web service reliability issues. It first introduces a strategy for addressing the problem and then takes a deep dive into the solution. The underlying strategy to mitigate the problem is to isolate the Internet Web service code from an application and centralize access to the external Web service so it can be more easily troubleshot and reconfigured. Here are the solution objectives: Many tools have made invoking a Web service as simple as making a synchronous function call in your application. The key to addressing the Web service reliability issue is abandoning the synchronous function call notion and thinking asynchronously. Asynchronous messaging is an integration approach extensively covered in the book Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions. A complete discussion of asynchronous messaging is beyond the scope of this article, so I'll summarize the key points pertaining to the solution. In asynchronous messaging, a sender transmits data known as a "message" and a receiver consumes it. A transmitted message moves from sender to receiver through channels. Channels are built using databases, message queues, file systemsanything capable of persisting and sharing data. A message is composed of two things: A message can take any physical form: XML, a record in a database, a serialized class, a file, and so forth. To understand the basic idea behind asynchronous messaging, look at the synchronous Web service example at a high level and examine how asynchronous messaging differs. When calling a Web service synchronously, the consumer (caller) performs all the following actions in the same running process: Being synchronous, the actions above take an all-or-nothing approach. All of the actions must happen successively, successfully, and in a timely fashion to complete the process. Asynchronous messaging is different. Each action or group of actions can be handled by a separate process or class. So, for example, one process may handle collecting and packaging the parameters and then post the packaged parameters to a channel to be picked up by another process that invokes the Web service. Each class or process is responsible only for performing its assigned segment in the process. Unlike the all-or-nothing approach, a single process cannot fail all segments. If it sounds like object-oriented design, it's because it is like object-oriented designonly on a larger scale. So, how do you apply an asynchronous message to fix the unreliable Web service problem? Applying lessons from the Enterprise Integration Patterns book and using notation from it, Figure 1 shows a design that outlines the solution. Figure 1. A Design Outlining the Solution Note the multiple channels, endpoints, and gateways, but only one router. Also note that it uses the database symbol to show that the gateway accesses the database of the application. Another way of expressing this is to use the "Claim Check" symbol. Using the Figure 1 design achieves the following objectives: Now, see how the company I work for implemented the design. Traditional integration projects utilize some piece of middleware or message queue application. The endpoints and channels for my company's service were implemented using Transact SQL and SQL Server. Because my company's applications are all SQL Server-based, SQL Server technologies was a natural choice for easy integration with our application environment. The technology behind the solution functions as follow: Because the router is the heart of the solution, you should focus on the router implementation. The router consists of the classes in Figure 2, which depicts their hierarchical relationship. Figure 2. Hierarchical Relationship of Router Classes The classes have the following roles: Channel location information and gateway information are loaded in the config file of the Windows service. You can download the source code, so I'm going to focus only on the key functions in the service. As discussed previously, the GatewayRouter performs all of the routing functions, including executing the appropriate gateway. To initiate routing, the GatewayRouterExecution calls Init and then DoRouting in GatewayRouter. DoRouting calls RouteMessageFor on each of the configured channels. Each channel can have multiple messages, so RouteMessageFor calls InvokeGateway for each channel message. GatewayRouter is the heart of the Windows service and the heart of GatewayRouter is the InvokeGateway function: As you can see, code is included to retry the Run function should some sort of failure occur. The Windows service assumes all gateways inherit from a common C# interface: IXmlServiceGateway. On a class implementing IXmlServiceGateway, the Run function performs all the actions necessary to invoke the Web service and write the response data back to the application database. Giving the gateway access to a database so it could retrieve parameters and save responses greatly simplified the process, allowed for easier transaction processing, and eliminated the need to pass XML messages between the queues. Another key section of code is the AddGateway function: AddGateway uses functions from the System.Reflection namespace to load the assembly containing the Gateway class, which creates an instance of the Gateway class and assigns the instance to an IXmlServiceGateway interface. GatewayRouterExecution executes its StartRouting function on a thread inside GatewayRouterController: As you can see, StartRouting does not terminate until it is signaled to do so. The class GatewayRouterSignal housed inside the GateRouterController and shared with the other classes is used to signal whether the Windows service must terminate or Routing must cease because it is outside of the service window. The GatewayRouterControl is the Windows service. The Windows service code calls the Start and Stop functions on GatewayRouterControl to start and stop the service. As stated previously, GatewayRouterControl runs the GatewayRouterExecution on a separate thread. The following snippet of code executes the GatewayRouterExecution class on the thread: For more information on multithreading, check out following articles: "Multithreading in .NET Applications," "Multithreading in .NET Applications, Part 2," and "Multithreading in .NET Applications, Part 3". For more information on constructing a Windows service, read "Creating a Windows Service in .NET". Before applying the ideas in the solution described here, consider the following ideas: Web services can be unreliable. A Web service problem can exist on the client side, server side, or the Internet itself. You can mitigate Web service reliability problems by using an asynchronous messaging approach implemented inside a Windows service. Download the code that accompanies this article. Jeffrey Juday is a software developer with Crowe Chizek in South Bend, Indiana. He has been developing software with Microsoft tools for more than 12 years in a variety of industries. Jeff currently builds solutions using BizTalk 2004, ASP.NET, SharePoint, and SQL Server 2000. You can reach Jeff at jjuday@crowechizek.com.
A Windows Service Solution for Unreliable Web Services
June 28, 2006
A Strategy to Mitigate the Problem
Asynchronous Messaging
The Asynchronous Message Solution
Click here for a larger image.
Service Overview
Router: The Heart of the Solution
Loading a Gateway
IXmlServiceGateway gateway = null;
bool tryWSInvocation = true;
int tryCount = 0;
try
{
gateway = GetGateway(info);
while ( tryWSInvocation )
{
gateway.Run(info.ServiceInstanceID);
//The assembly can indicate that a retry is possible,
//the router determines how many times it will attempt to
//call run.
if (gateway.CanRetryRun() && tryCount < _wsRetryCount)
{
tryWSInvocation = true;
}
else
{
tryWSInvocation = false;
}
++tryCount;
}
//This was added for administration troubleshooting and reporting
WriteGatewayResultsToDB (dbConn,info,gateway.CurrentMessage);
if (gateway.IsErrorToReport() )
{
LoggingFunctions.WriteToLog_Error(gateway.CurrentMessage);
}
Assembly assm = Assembly.LoadFrom(info.AssemblyName);
//Assembly has no public constructor
IXmlServiceGateway gateway;
gateway = null;
gateway = (IXmlServiceGateway) assm.CreateInstance(info.ClassNameSpace);
gateway.Init(info.ServiceTypeID);
_gateways.Add (gateway);
Controller: Multithreading
_signal.ContinueRouting = true;
while ( _signal.ContinueRouting )
{
_router.DoRouting();
//If discontinue signal was given don't sleep
if ( _signal.ContinueRouting )
{
Thread.Sleep(_delayRoutingInterval);
}
}
_threadExec = new Thread(new ThreadStart(_routerExec.StartRouting));
_threadExec.Start();
_routingActive = true;
Applying the Solution
Mitigate Web Service Reliability Problems
Download the Code
About the Author