Browse DevX
Sign up for e-mail newsletters from DevX


Building WCF Services for Deployment in Transiently Connected Networks : Page 5

Users increasingly rely on their applications to work both on site and on the go, so they can remain productive anywhere and at any time—regardless of how they connect to the network.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Implementing the LibroLogic Service Gateway
The Gateway pattern is common when integrating services into existing applications. Martin Fowler describes this pattern in detail in his excellent book, Patterns of Enterprise Application Architecture. Service Gateway is a specific type of Gateway pattern adapted for use in service-oriented architectures, and as such, its major concern is encapsulating a consuming application's access to external systems. The Service Gateway pattern is also covered well in the Microsoft Patterns & Practices paper titled, "Enterprise Solution Patterns using Microsoft .NET." A Service Gateway is a wrapper around the component or service that abstracts call details to a service (or in-process component for that matter). In addition to providing location transparency to the consumer, a gateway insulates service consumers from the transport details and service types that the service boundary exposes. This is always a good idea because service details inevitably change, as do potential service providers; you can protect your business layer (and thus the application itself) by decoupling it from such details.

Test harnesses are very useful in communicating functionality and demonstrating progress for services which are inherently abstract to the typical business user.
In this scenario, the Service Gateway pattern is particularly useful for insulating the details of which endpoint you are calling from the presentation code.

The LibroLogicServiceGateway class is located in the LibroLogic.UI.ServiceGateways project. The definition of the methods supported by the ILibroLogicServiceGateway gateway is shown below:

using System; using System.Collections.Generic; using System.Text; using LibroLogic.UI.BusinessEntities; namespace LibroLogic.UI.ServiceGateways { public interface ILibroLogicServiceGateway { Book GetBook(string uniqueIdentifier, bool online, bool onsite); Book[] GetBooksByTitleKeyWord(string title, bool online, bool onsite); void PurchaseBook(string storeId, string orderNumber, int quantity, PaymentType paymentType, Book book, bool online, bool onsite); } }

Listing 8 shows the implementation for the current service provider(s). Notice that the methods included in the LibroLogicServiceGateway are very similar to those defined in the IInventoryOps and IRetailOps Service Contracts. This is the case because in this scenario, we have control of both the Big SOA and Little SOA aspects of the LibroLogic application. However, in cases when you are integrating a service from a vendor or are integrating an application or service that for political or other reasons is beyond your control, it is likely that the method names you come up with for your service gateway will differ, if not for the simple fact that the operations provided by the service may not be all that intuitive to your own domain model. In addition, should the service provider ever be replaced, any clients behind the ILibroLogicServiceGateway interface will be completely shielded from change.

Because I designed both sides of the wire, the only difference between the method signature of the operation at the service and the members defined in the gateway interface is the addition of two Boolean parameters: online and onsite:

public interface ILibroLogicServiceGateway { Book GetBook(string uniqueIdentifier, bool online, bool onsite); Book[] GetBooksByTitleKeyWord( string title, bool online, bool onsite); void PurchaseBook(string storeId, string orderNumber, int quantity, PaymentType paymentType, Book book, bool online, bool onsite); }

You could easily argue that these parameters are a design smell and that the network status detection code has no business in the presentation tier, or at least not in the Windows Forms code-behind. I wholeheartedly agree! However, keep in mind that this is merely a test harness and I wanted to keep the user interface as simple as possible while illustrating the use of the System.Net.NetworkInformation API without getting too far away from the service, which is the focus of this article. As they used to tell us in the Army: "This is for illustration and illustration purposes only."

The LibroLogicServiceGateway simply implements the ILibroLogicServiceGateway interface. As long as clients bind to the ILibroLogicServiceGateway, they will have a binary shield protecting them from changes beyond the service boundary.

Here is the implementation of PurchaseBook. As seen in Listing 8, you will use the method to handle both the purchase of a book and the flagging of a book when it is being moved off site. The decision as to which endpoint to use for the proxy instantiation is based on the value of the online and onsite parameters that are passed in from the LibroLogicClient instance. The ability to dynamically choose which endpoint (transport) to use is facilitated by the RetailOpsClient constructor overload, which takes the name of the endpoint to use when preparing the communication channel:

public void PurchaseBook(string storeId, string orderNumber, int quantity, string paymentTerms, Book book, bool online, bool onsite) { LibroLogic.UI.ServiceGateways. localhost.RetailOpsClient proxy; if (online & onsite) { proxy = new LibroLogic.UI. ServiceGateways.localhost. RetailOpsClient("RetailTCP"); } else if (online & offiste) { proxy = new LibroLogic.UI. ServiceGateways.localhost. RetailOpsClient("RetailHTTP"); } else { proxy = new LibroLogic.UI. ServiceGateways.localhost. RetailOpsClient("RetailMSMQ"); } }

It's also important to understand that there are two representations of the Book class. Earlier, I walked you through the Book Data Contract, which is defined within the context of the service and supports SOAP serialization of the opt-in properties. However, keep in mind that you use the Book Data Contract for interoperability purposes only; it has no business bleeding into the local application's business domain. So, in essence, you have two classes called Book that may look the same, but are completely different due to their namespaces. An added benefit of the Service Gateway pattern is that it serves to address this very common transformation problem. As subtle as it might be, it is important to note that the Book parameter included in the methods provided by the LibroLogicServiceGateway is of type LibroLogic.UI.BusinessEntities, not http://LibroLogic.com/services/09/2007. Listing 8 contains two additional methods not defined in the interface that handle this translation: MapLocalBookToProxy and MapProxyBookToLocal.

Contending with such translation subtleties is important if you are truly building service-oriented applications. The temptation to distribute service assemblies containing common types to the client is a hangover from pre-SOA techniques, and you should avoid it. Furthermore, allowing types behind the service boundary to bleed into the consuming application's business domain is a recipe for integration spaghetti, which you should also avoid. Making a habit of using the Gateway pattern will help insulate you from both.

Implementing the Search and Purchase Event Handlers
When a user enters an ID to search for a particular book, the test harness calls the btnSearchById_Click method to handle the Click event.

Similarly, when the user enters a title to find books that match that search string, the test harness invokes the btnSearchByTitle_Click event handler.

The purpose of the event handlers is to wire the Click event to the functionality that is responsible for handling the event. Recall that the IRetailOps Service Contract defines two methods specifically designed to handle these kinds of requests:

[OperationContract(IsOneWay = true)] void PurchaseBook(string storeId, string orderNumber, int quantity, PaymentType paymentType, Book book);

Instead of instantiating the proxy and calling these operations directly, the event handlers simply channel the call to the appropriate method on the LibroLogicServiceGateway. The following code demonstrates the invocation of the PurchaseBook method on the gateway within the btnSubmitPurchase_Click method (the complete code for the test harness is provided in Listing 7):

ILibroLogicServiceGateway gateway = new LibroLogicServiceGateway() as ILibroLogicServiceGateway; gateway.PurchaseBook(storeNumber, orderNumber, quantity, paymentType, book, Online, OnSite)

A gateway allows for the consumer of a service to be insulated from the transport details and service types that the service boundary exposes.
Each event handler works the same way. The beauty of this design is that details of which endpoint to call are all abstracted from the user interface, making the code consistent, readable, and easy to understand. The user interface has no idea which endpoint is being used or that the test harness may queue this particular call.

Surviving Transient Network Conditions
With the focus on this article on queued services, let's concentrate on the ability to queue messages when the network is offline. With the LibroLogic application up and running (along with the LibroLogic Service, of course), you can test the ability to query for books using both supported methods. For example, when you enter a search term, such as "computers," you should get a list of books that match the criteria as shown in Figure 7. Make a note of the TitleId for one of the books. The TitleId serves as the unique identifier for the book, which in most cases would be a UPC code or ISBN number.

Figure 11: Use TCP when the user is both online and on site sending purchase messages directly to the service.
Click the "Purchase" tab and enter the TitleId from the book in the grid on the Search tab. Enter a quantity of 1 and select the "Credit Card" check box. Click the "Submit Purchase" button. A message should appear in the Messages section indicating that the request was successful as shown in Figure 11. In this case, the RetailTCP endpoint was used because the status indicates that the application is both online and on site.

Note the status of the icon in your task bar that represents your active network connection and makes sure it is online. Now, with the LibroLogic test harness running, go to My Network Places, right-click, and then click Properties. Find your network connection and click "Disable" as shown in Figure 12. Within a few moments, the status bar on the test harness will change to indicate that the network is now offline. Your task bar network icon (see Figure 13), should confirm this. Also notice that the "Search by Title" and "Search by Id" buttons on the Search tab are disabled, which is necessary because those features require a request-reply messaging pattern that is not supported in offline mode. Attempting to use these features in offline mode would result in an exception.

Figure 12: The network interface is disabled to simulate the user being offline.
Figure 13: The icon on the taskbar indicates that the network interface is disabled.
At this point, the application is simulating that the network is down. However, because the LibroLogic service is running on the same machine, it will happily pick up messages from the queue. To complete the scenario, close the LibroLogic Service host by exiting the console window.

Figure 14: The user is able to submit purchase orders despite the network being unavailable.
Now, click the "Purchase" tab and enter a valid TitleId, along with the other information, ensuring that you chose a payment method. Click "Submit Purchase." As shown in Figure 14, a message appears indicating that the purchase message has been sent! Despite the network being down and the service being completely unreachable (at least at the moment), from the client's perspective, the ability to purchase a book is still fully supported. While the application is in offline mode, it is still operational, albeit with limited functionality.

Feel free to click the "Submit Purchase" button a few more times, changing the values you entered in the corresponding text boxes (note that the Order Number must be unique or it will violate a constraint on the database). The messages representing the purchase request have been queued locally on the client machine. To verify this, open the Computer Management MMC snap-in by right-clicking "My Computer," and then clicking "Manage." Toward the bottom of the tree, you will see a group called "Applications and Services." Expand this group and expand the group under it called "Message Queuing." Under "Message Queuing," expand "Private Queues." As seen in Figure 15, you will see a queue called "LibroLogicServiceQueue," and in the Queue Messages folder, you will see a message for each purchase request.

Figure 15: The private queue provides durable delivery assurance, even when the service is unavailable.
Now let's simulate the network coming back on line. With the Computer Management MMC snap-in still running (and the MSMQ groups expanded), find the disabled network icon on your task bar. The disabled network icon should resemble something similar to Figure 13. Enable your network card by right-clicking the disabled network icon on your task bar and then clicking "Enable" as shown in Figure 16. The status changes back to indicate that the network is online. Again, you will notice that in just a few moments, the status bar on the test harness will change to indicate that the network is online. Although the network is now online, remember that you closed the service host. As a result, it will not process the queued messages until the next time it starts. Start it now. Once you do, for every purchase message in the queue, you should see an entry in the console hosting the service similar to Figure 17. Finally, look in the Queue Messages folder under the LibroLogicServiceQueue, and you will notice that the queue is now empty. The messages have been delivered to the LibroLogic Service automatically.

Figure 16: Enabling the network icon.
Figure 17: After the network interruption, the service processes messages from the queue.
In addition, to verify that the messages have indeed been received, on the SQL Server machine that has been configured for the LibroLogic Service, feel free to open the Pubs database and open the "Sales" table. You will see an entry for each of the purchase requests.

As you have seen, adding support for queued services to your WCF applications is not very difficult to do and adds increased reliability for your users. Given the elegance of the WCF hosting and configuration architecture, you can build robust applications with a primary focus on delivering business value, leaving many of the configuration details (hosting, transport, bindings, etc.) to a deployment-time decision. This key strength of WCF yields significant productivity.

In addition, you've seen an overview of the System.Net.NetworkInformation namespace, which provides a number of APIs for discovering network specific information and how you can use this information to determine the appropriate binding to use at run time.

I also showed you how to write a lightweight test harness to exercise the service and demonstrated an implementation of the Service Gateway design pattern to shield your clients from the details of the services they're interacting with.

Last but not least, I showed you how to leverage Microsoft Message Queue to enable your services to support queued calls. While the ability to queue messages in a disconnected scenario is a key way to add enhanced reliability to your applications, there are still some gems in WCF that enable you to build even more robust applications that are reliable across various transport protocols, and ensure that—regardless of the outcome of a message—the underlying system remains in a consistent state. I'll explore more of these features in detail in upcoming articles, so stay tuned!

Rick G. Garibay is a software architect and seasoned application/system developer with a primary focus on middle-tier components and services.With over seven years experience delivering solutions in various industry sectors, including financial services, automotive retail and environmental health, safety and crisis management, Rick holds various Microsoft credentials including MCAD .NET and is an active speaker and member of the greater Phoenix .NET community.
Thanks for your registration, follow us on our social networks to keep up-to-date