The Traveling Book Salesman (or Woman)
My wife loves to read fiction. Although her reading pace has slowed down significantly since we had children, her idea of fun is still to go out to the used bookstores and book fairs to feed her reading habit. In fact, we have shelves and shelves full of paperback novels that she hasn't even touched yet. Some get read, some get left on the shelf, and others are recycled back to one of these bargain booksellers. I am always amazed at what a community there is around the buy/sell/trade paperback book market. For example, a popular novel by a heavy hitter like James Patterson or Tom Clancy might get you two moderately popular books in trade, or you may get $3 toward the purchase of a new or used book. A not-so-popular book may get you 25 cents—if anything at all. These stores always seem to be doing good business and, if you've ever been to a bargain book fair, you know how crazy the crowds can be. People love books and people love a good bargain.
|You should strive to create your artifacts in a manner that is intuitive and reflects the solution architecture.|
One of the things I've found particularly interesting (ok, it annoys the daylights out of me) is that very few of these bargain book stores have their books inventoried. If you are looking for The Bourne Identity
by Robert Ludlum, you have to walk over to the Fiction shelf and search by last name. This is so 20th century!
Let's build a system that streamlines retail and inventory operations by connecting the sales process with an inventory database using .NET 2.0, WCF, MSMQ, and SQL Server 2005.
I've created a simple service-oriented application called "LibroLogic" that streamlines retail and inventory operations by connecting the sales process with an inventory database using .NET 2.0, WCF, MSMQ, and SQL Server 2005.
When a customer comes in to find a book, LibroLogic will do a search against the LibroLogic Database via the LibroLogic Service and give the customer a definitive answer as to whether the book exists somewhere in the store. Better yet, when a customer comes in to sell or trade a book, LibroLogic will be able to determine how many books by that title (if any) are already on hand, allowing the sales associate to base the trade-in value on this simple piece of business intelligence that will be provided by the LibroLogic Service, a WCF service that supports the LibroLogic application. Since this type of search will happen on site, where the UI, service, and database are deployed, the LibroLogic application will communicate with the LibroLogic Service using TCP. For intranet scenarios, this is the best choice because it is the fastest, most efficient transport protocol available to WCF where reliability is required.
Likewise, when a book is sold on site, the application will use TCP to communicate with the LibroLogic Service.
When a store that uses the software takes inventory on the road to participate in a book fair, using the LibroLogic software, a clerk can flag a book in inventory as being off site before the book leaves the store. Again, the application will use TCP in this scenario because this action will likely happen when on site.
Any time LibroLogic makes a call to the LibroLogic Service, it will intelligently detect the status of the network to ensure that the sales associate can remain productive regardless of the state of the network. The clerk can remove books that are sold off site from inventory in real time when possible. Like the example of the long line at Starbucks, this situation is far from ideal because it may take several hours or days for the service to update the state of the book in inventory, but it is certainly better than not being able to sell the book at all or depend on a manual update to inventory reflecting that the book has been sold.
To summarize, LibroLogic addresses the following features:
Writing the LibroLogic Service
- When a sales associate is on site, they may search inventory for a book by ID or title keyword using the fastest network connection available.
- When a sales associate is on site, they may sell a book provided it is in inventory using the fastest network connection available.
- When a sales associate is on site, they may flag a book as being off site to denote the fact that a book is not in the store using the fastest network connection available.
- When a sales associate is not on site, they may sell a book (provided it is in inventory) regardless of the state of the network.
|Figure 1: The LibroLogic Service is organized into layers consisting of the service interface, business, data access, and database.|
As mentioned above, the three primary activities that the UI will provide is the ability to look up a book by a unique identifier or keyword, flag a book as being off site, and notify the inventory system of a purchase. These first two activities might take place at the store, but the latter may happen while off site.
The service will be distributed into a layered architecture as shown in Figure 1
. In keeping with the SOA tenet of autonomy, the LibroLogic Service (service, assemblies, and database) is a self-contained, single logical (and physical) unit so you can deploy it anywhere on the network with little administrative effort. While you should always strive for this kind of assembly and resource allocation, it is common to reuse Business Components, Business Entities, Data Access Components, and the database, especially in legacy systems or where underlying layers have not been factored optimally. As with all decisions in building out a solution architecture, you must determine the compromises of factoring out the functionality into a more autonomous unit of deployment versus the benefit of doing so, which will often come down to budget and calendar time.
|Figure 2: The solution for the LibroLogic Service is organized into projects that intuitively represent the role of each resulting assembly.|
Regardless, you should strive to create your artifacts in a manner that is intuitive and reflects the solution architecture. Figure 2
shows the sample application that accompanies this article and that you can download from my site
. You should be able to infer what each project/assembly does from the names. I will refer to those project names in the description of the sample solution in this article.
Define the Book Data Contract
The first step is to define the data transfer object (DTO) for describing a book. The Data Contract is important because it will model the business domain—a book in this case—which is the cornerstone of the LibroLogic application. In WCF, Data Contracts are DTOs that are either parameters within an Operation Contract or are used as a return type. Listing 1
represents the Book Data Contract that you will use to represent a book that is inventory.
I've packaged the Book Data Contract within the LibroLogic.BusinessEntities class library project and provided it within the solution download. You will notice that references to the System.ServiceModel.dll
assemblies are present. These assemblies are core to the .NET Framework 3.0 Runtime Components, and specifically, WCF.
|Figure 3: The Book Data Contract as serialized by the System.Runtime. Serialization. DataContractSerializer class.|
The role of the Book Data Contract is simple. It describes book information and tells the DataContractSerializer how to handle the serialization from memory representations of Book into wire format using SOAP and XML. In fact, if you run the following code, you can see what the XML will look like as it is sent across the wire (see Figure 3
Define the IInventoryOpsService Contract
LibroLogic.BusinessEntities.Book book = new
using (System.Xml.XmlTextWriter writer = new
DataContractSerializer serializer = new
With the Book Data Contract in place, I've defined the Service Contract for inventory-related activities supported by the LibroLogic Service. Visual Studio stores the Service Contracts for the LibroLogic Service in the LibroLogic.Interfaces project. This contract will support the first and third user features as previously defined. The Service Contract is called IInventoryOperations and consists of three methods as shown below:
Define the IRetailOps Service Contract
public interface IInventoryOps
Book GetBook(string uniqueIdentifier);
I defined the IRetailOps Service Contract to support the second and fourth user feature, the latter of which deals with the ability to manage a retail sale in a disconnected manner. I designed the IRetailOps Service Contract to support an endpoint powered by a WsHttpBinding
, or NetMsmqBinding
binding. Specifically, notice that I have set the IsOneWay
property on the PurchaseBook Operation Contract:
public interface IRetailOps
[OperationContract(IsOneWay = true)]
void PurchaseBook(string storeId, string
orderNumber, int quantity, PaymentType
paymentType, Book book);
This distinction is important because the NetMsmqBinding binding that powers the Service Contracts must consist of operations that you mark as one-way. The reason for this is that no logic is tied inherently to the endpoint. When you dispatch a message to a queue, you are merely sending it on its way to its ultimate destination. It may reach the destination immediately, after an elapsed period of time, or not at all. As a result, the call is treated as one-way or publish/subscribe. When this requirement is not met, the Service Model throws an InvalidOperationException exception, faulting the channel.
Implementing the IInventoryOps and IRetailOps ServiceContracts
|Service Contracts that are powered by the NetMsmqBinding binding must consist of operations that you mark as one-way.|
With the Service Contracts for inventory and retail related activities defined, I have implemented the contracts in the LibroLogicService. You will find this class in the LibroLogic.Services project.
As you can see in Listing 2
, the implementation is fairly straightforward. In accordance with the solution architecture depicted in Figure 1
, the implementation calls the appropriate methods on the InventoryManager and RetailManager components within the LibroLogic.BusinessComponents assembly. Each business component accordingly channels that call to the corresponding methods within the BookDA data access component located in the LibroLogic.DataAccess assembly. While not the focus of this article, I've provided the code for the RetailManager and InventoryManager business components in Listing 3
and Listing 4
. I also wrote a data access component called "BookDA" (Listing 5
). You will notice references to Microsoft.Practices.EnterpriseLibrary.Data, which is a namespace for an assembly that ships with Microsoft Enterprise Library
. You can download it at no charge. This namespace contains several ADO.NET helper classes that saved me a lot of time. Speaking of time savers, I also used CodeSmith
to generate all the custom stored procedures I wrote (er, generated) for this article.
As with all WCF services, notice the fact that the underlying assemblies are part of a service, which has no bearing on the implementation of the service whatsoever. These "Little SOA" implementation details would likely resemble similar characteristics if you were writing a purely component-oriented application. As a matter of fact, much of the same best practices behind or within a service still apply. This distinction is important because "Little SOA enables Big SOA" (Bustamante). That is, without services, you can't have a service-oriented architecture. There are different aspects and skill sets that apply to Little SOA as opposed to Big SOA. The "Big SOA" aspects are most often in context whenever someone talks about Service-Oriented Architecture in general, because it usually involves the integration of disparate service-oriented applications. That said, the ability to think conceptually in terms of both "Big SOA" and "Little SOA" will give you a tremendous advantage in designing and implementing service-oriented applications that are sustainable.