Exploring the LibroLogic Test Harness
I am a big fan of using lightweight test harnesses to demonstrate service functionality. Test harnesses are useful for communicating functionality and demonstrating progress for services that are inherently abstract to the typical business user. I typically build them using Windows Forms because I can easily build some visually appealing bells and whistles into the interface to impress customers. In addition, getting into the habit of creating lightweight test harnesses for your services means that you have a smoke tester for exercising your services. Having test harnesses available for each service that support a business process can be a godsend when troubleshooting a problem within a business process that is distributed across multiple services behind a service boundary. If your business process is made up of half a dozen services and you want to know where the problem lies, you can exercise each service using its respective test harness, isolate the point of failure, and begin a very focused and effective debugging and troubleshooting session (or, better yet, prove that your service is working!).
|Figure 7: The search tab on the test harness provides the ability to exercise search operations on the service when the network is online.|
The user interface for working with the service is very basic, as it is takes a minimalist approach to showing the high-level functionality that the service provides. This said, if there are any WPF gurus out there that want to do a mashup, shoot me an email.
In exploring the test harness, Figure 7
shows the application with the "Search" tab selected. The search feature allows the user to enter either a unique identifier for the book (commonly a UPC code or ISBN number, however in this case I will use the ID used by the Pubs
database) or a title keyword. Also notice in Figure 7
the status bar that indicates the status of the test harness. Certainly, there are several additional features that you could add to the application, but the sole purpose of this client is to demonstrate the core functionality that addresses the features previously discussed.
The "Purchase" tab allows a user to enter an ID for a given book and select a payment method. Again, this is a minimalist approach to demonstrating the core functionality of the service. Therefore, this form consists of a text box for the ID and a few check boxes to indicate the payment method. You will notice that I've labeled one of the check boxes "Flag." This check box allows the user to indicate that the book has not been sold, but is being flagged to indicate that the book has left the store despite not (yet) being sold. Figure 8
demonstrates the "Purchase" screen.
|Figure 8: The purchase tab provides the ability to exercise one-way calls on the service, regardless of the user's location or network status.||
|Figure 9: The status of the network connection and whether the application is running locally or remotely is displayed to the user using a status bar.||
One other important point of interest is the status bar shown in Figure 9
. This control is visible regardless of the tab that is active. Tts sole purpose is to indicate whether a network connection is available, and if so, whether the application is running on site or off site.
Detecting the Status of the Network at Run Time
|Figure 10: The endpoint will be determined at run time based on the state of the network and the location of the user.|
There are a number of decisions that need to be made before you call the WCF proxy. Figure 10
presents a matrix for determining which endpoint you should use given a network and location condition. For instance, if the network is online and the application is running on site, you should use the InventoryTCP
endpoint to service search requests. However, if the application is running off site and a network connection is present—assuming the user can access the Internet—you should use the InventoryHTTP
endpoint to service the same search requests.
So, the first thing you must do before servicing a search request is figure out if a network connection is present. There are a number of ways to go about this, but it turns out that the .NET Framework 2.0 introduces a new namespace called System.Net.NetworkInformation that includes a class called NetworkInterface that provides just this kind of information. In fact, if you want to query whether the primary network interface is available, you can simply call a method called GetIsNetworkAvailable
as shown below:
method returns a Boolean value to indicate whether the network interface is online and functional. If you have more than one network connection, you can simply call the GetAllNetworkInterfaces
method, which will return an array of NetworkInterface objects that can be further interrogated as needed. To do so, simply call the GetIPProperties
method on the NetworkInterface class. The GetIPProperties
method will return an object that implements IPInterfaceProperties. This interface provides nifty information such as IP, DNS, and Gateway addresses—exactly the information you would need to determine if the application is being run on site or remotely.
And just when you thought you could take no more, the System.Net.NetworkInformation namespace also provides a class called NetworkChange, which supplies an event called NetworkAvailabilityChanged
that fires whenever the state of the network changes (i.e., a network connection is lost). NetworkChange also provides an event called NetworkAddressChanged
that fires when an IP address changes. With either event, the runtime checks a list of subscribers and notifies the configured delegate—just as with any .NET event. In this case, your test harness will use delegates to intelligently act upon this information as it happens.
I was so impressed when my mentor and friend, Juval Lowy, showed me this technique that ever since I've been resolved to write about it. As you (hopefully) are starting to see, at your fingertips lies a tremendously powerful API that, when combined with WCF, allows you to develop applications with intelligence that just a few years ago would have been significantly more complex to implement.
shows the code for the test harness. One of the first things you will notice is two properties, Online
, both of which are thread-safe. The reason for this is that the NetworkAvailabilityChanged
events will call their corresponding delegates using threads from the thread pool. As such, support for multithreaded access is a must.
property simply returns true
to indicate whether the application has a network connection:
public bool Online
m_Online = value;
property works the same way, signaling if the location of the user is other than the configured location that is considered on site:
public bool OnSite
m_Onsite = value;
Within the constructor of the LibroLogicClient Windows Forms class, note the following code that sets the value of the Online
properties, subscribes to the events of interest, and provides and initializes the status bar using the appropriate methods:
bool online = false;
bool onsite = false;
online = NetworkInterface.GetIsNetworkAvailable();
onsite = QueryLocation();
method simply sets the Online
property and subsequently calls a method called UpdateStatusBar
void UpdateNetworkAvailableStatus(bool online)
Online = online;
method updates the text on the m_StatusBar
control (which is rendered at the bottom of the LibroLogic UI as shown in Figure 7
and Figure 8
). You must synchronize this update with the UI thread because the events fire from the thread pool. The MethodInvoker
method handles the synchronization and updates the status bar with the respective string value:
private void UpdateStatusBar()
m_StatusBar.Text = "Test";
string status = Online ? "Current Status: Online" :
"Current Status: Offline";
string locStatus = OnSite ? "Onsite" : " | Offsite";
m_StatusBar.Text = status +
Recall that in order to support the ability to detect intermittent network status at runtime, you must subscribe to the NetworkAvailabilityChanged
events. I have named the handlers for these events OnNetworkAvailabilityChanged
method is of the NetworkAvailabilityChangedEventHandler delegate type and calls the UpdateNetworkAvailableStatus
method just discussed:
void OnNetworkAvailabilityChanged(object sender,
method is of the delegate type NetworkAddressChangedEventHandler. Any time you call this handler, it will simply query the IP information using the QueryLocation
method and update the status bar in much the same way as the UpdateNetworkAvailableStatus
method. You can see all this code in Listing 7
void OnNetworkAddressChanged(object sendes,