Step by Step

Design and Build Message-oriented Web Services for a Service Oriented ArchitectureFramework

asp:cover story

LANGUAGES: C#

ASP.NET VERSIONS: 1.0 | 1.1

 

Step by Step

Design and Build Message-oriented Web Services for a Service Oriented Architecture Framework

 

By Jeffrey Hasan

 

The purpose of Web services in a Service Oriented Architecture (SOA) framework is to exchange and process XML messages, not simply to act as hosts for Remote Procedure Call (RPC)-style methods. The difference is that messages are bound to rich and complex operations, whereas RPC-style methods simply return a discrete result that is directly correlated to a specific set of input parameters. For example, a message-oriented Web method will accept a stock ticker symbol and return a detailed stock quote in response. But an RPC-style Web method will simply return the result of an arithmetic operation on its input parameters.

 

Unfortunately, development tools such as Visual Studio.NET place a method-centric focus on Web services that causes you to lose sight of the bigger design picture and to take the underlying infrastructure for granted. It s very easy to build a Web service by creating an .asmx file and then throwing together several loosely related RPC-style Web method implementations. However, this is the wrong design approach because such a Web service fails to provide an integrated set of message endpoints. In simpler terms, the Web service fails to provide a service. The correct design approach is always to think in terms of operations and XML messages, and to consider how the Web service methods work together to provide a service.

 

This article is designed to challenge you to set aside what you have learned about Web services development and open your mind to a different design approach one that is based on integrated XML messages, not on RPC-style methods.

 

How to Build Message-oriented Web Services

There are six basic steps involved in building a message-oriented Web service; following is a brief description of each.

 

Step 1: Design the messages and the data types. Conceptually design what the messages and data types will look like. UML class diagrams are the best way to capture this information.

 

Step 2: Build the XSD schema file for the data types. Use an XML designer tool to build the XSD schema file for all the data types that are exchanged by the Web service methods. Visual Studio.NET s XML Designer is a good tool, but you can use any XML Designer tool with which you are comfortable.

 

Step 3: Create a class file of interface definitions for the messages and data types. The interface definition class file provides the abstract definitions of the Web service methods and its data types. This class file derives from the System.Web.Services.WebService class, so it can be readily implemented in a Web services code-behind file. The .NET Framework provides a command-line tool called xsd.exe for generating an interface definition class file based on an XSD schema file. This will manually generate class definitions for the data types. You can add this class file to your Web service project and then manually insert abstract definitions for the Web methods.

 

Step 4: Implement the interface in the Web service code-behind file. Your hard work in Steps 1-3 pays off as you are now ready to implement code for the Web methods. The Web service .asmx code-behind class derives from the System.Web.Services.WebService class by default, as does the interface definition class file from Step 3. So you can derive the .asmx code-behind class directly from the interface definition class instead, and then implement code for each of the methods.

 

Step 5: Generate a proxy class file for clients based on the WSDL document. Web services have no reason to exist unless they are being used by clients. In this step you generate a proxy class file based on the Web service WSDL document so that clients know how to call your Web service, as well as what messages and data types will be exchanged. The wsdl.exe command-line tool will automatically generate this proxy class for you based on the WSDL document.

 

Alternatively, Visual Studio.NET will automatically generate the WSDL document for you, so no manual work is required. VS.NET will dynamically generate the proxy class file for you when you add a Web reference (for your Web service) to a client project. I prefer to manually generate the proxy class file so that I can either alter it or have it ready for clients who are using a development tool without code-generating wizards. However, for the purposes of this article, auto-generation of the proxy class file works just fine.

 

Step 6: Implement a Web service client using a proxy class file. This final step hooks a client to your Web service. If you are using Visual Studio.NET simply add a (dynamic) Web reference to the Web service in your client project; this will automatically generate the proxy class file for you. This wizard will also make the necessary adjustments to your application configuration file to record the location of the Web service. The client essentially does nothing more than delegate method calls out to the Web service. Valid clients include Web applications, Windows Forms applications, Console applications, or even other Web services.

 

Now that we ve reviewed the six basic steps for building a message-oriented Web service, it s time to implement one. The remainder of the article shows you how to do this.

 

Design the XML Messages and XSD Schemas (Step 1)

XML messages represent the operations that your Web service supports and they correlate to implemented Web methods. XML messages don t contain implementation logic. Instead, they simply document the name of an operation and its input and output types. XML messages must be designed in conjunction with XSD schema files. The best starting point is to construct a UML diagram for the operation. Figure 1 shows a UML class diagram for the RequestQuote operation and its associated input and output data types.

 


Figure 1: A UML class diagram for the RequestQuote operation.

 

The UML class diagrams will map conceptually to XSD schemas so you don t have to sketch out any XML during the design phase unless it helps you to better visualize the XML messages and types. For example, Figure 2 shows what the Quote type will look like within a SOAP response (with the embedded namespaces omitted for clarity). For design purposes, you can simplify the XML, as shown in Figure 3.

 

MSFT

Microsoft Corporation

11/17/2003 16:00:00

26.12

24.68

25.49

25.15

-0.36

-0.0137

25.49

35

22

Figure 2: The Quote type as it appears within a SOAP envelope.

 

Figure 3: A simplified view of the Quote type XML.

 

Clearly it s a lot of work to sketch out even this simplified XML by hand, and it doesn t provide any additional value beyond what the UML diagram provides. In fact, it provides less because this sketched-out XML provides no type information. So the message here is that for efficiency you should design your XML messages using UML or any appropriate shorthand notation. This is the extent of the design work that s minimally required, and you should never shortcut this step.

 

Build the XSD Schema File (Step 2)

When you have established what your XML messages and data types will look like, it s time to start building them. XSD schema files are the building blocks for XML messages, so you need to design the schema files first. XSD schema files may be coded by hand, but it s easier to use a visual designer tool, such as Visual Studio.NET s XML Designer. To access the designer you simply add a new XSD Schema file to a project. Visual Studio provides both a visual design view and an XML design view. Figure 4 illustrates the visual design view for StockTrader.xsd, which defines all the data types for this article s accompanying StockTrader sample application (see end of article for download details).

 


Figure 4: The Visual Studio.NET XML Designer, showing the StockTrader XSD schema.

 

The XML Designer includes toolbox elements that you can drag onto the surface of the designer and then fill in, as shown in Figure 5. For example, it provides a toolbox element for XML complex types. Simply drag this element onto the designer and provide a name for the complex type. Then start specifying the included types by their name and type. When you are finished defining all the types, switch to the XML view to view the resulting XML. You can then copy and paste the XML into a notepad file and save it with an .xsd extension.

 


Figure 5: The Visual Studio.NET XML Designer Toolbox.

 

We don t need to build the XML message documents by hand because they are created as part of the WSDL document, which Visual Studio.NET will automatically generate. But we will need to code the abstract method definitions in an interface definition file so that the WSDL generator knows what XML messages to create. The interface definition file contains type definitions and abstract method definitions.

 

Create the Interface Definition Class File (Step 3)

The interface definition class file contains two important sets of information:

  • Class definitions for all custom types that are exchanged by the Web service.
  • Abstract class definitions for each operation that the Web service supports.

 

Figure 6 provides the code for an interface definition class file for the RequestQuote operation and its associated types.

 

using System;

using System.Web.Services;

using System.Web.Services.Description;

using System.Web.Services.Protocols;

using System.Xml.Serialization;

namespace StockTrader

{

public abstract class StockTraderStub :

 System.Web.Services.WebService

{

[WebMethod()]

[SoapDocumentMethod(RequestNamespace=

 "http://www.bluestonepartners.com/schemas/StockTrader/",

 ResponseNamespace="http://www.bluestonepartners.com/

 schemas/StockTrader/", Use=SoapBindingUse.Literal,

 ParameterStyle=SoapParameterStyle.Bare)]

[return: XmlElement("Quote", Namespace =

 "http://www.bluestonepartners.com/schemas/StockTrader/")]

public abstract Quote RequestQuote(string Symbol);

}

[XmlTypeAttribute(Namespace=

 "http://www.bluestonepartners.com/schemas/StockTrader/")]

public class Quote

{

public string Symbol;

public string Company;

public string DateTime;

public System.Double High;

public System.Double Low;

public System.Double Open;

public System.Double Last;

public System.Double Change;

public System.Double PercentChange;

public System.Double Previous_Close;

public System.Double High_52_Week;

public System.Double Low_52_Week;

}

}

Figure 6: The interface definition class file for the RequestQuote operation and its associated types.

 

Notice the following important points:

  • The definition file includes one stub class that encapsulates all operations, and then any number of additional classes for the data types.
  • The interface definitions for the operations are enclosed within an abstract class called StockTraderStub. The stub class derives from the System.Web.Services.WebService class, so it can be implemented in a Web service. In this listing it contains a single abstract function definition for the RequestQuote operation.
  • The definition file contains a separate class definition for the Quote type. This is how you are able to reference the Quote type from code-behind.

 

Interface definition files (IDF) can be generated two ways:

  • wsdl.exe. This command-line tool generates a full interface definition file (including abstract classes and types) based on a WSDL document.
  • xsd.exe. This command-line tool generates the type section only for the interface definition file based on an XSD schema file. You can use this auto-generated file as a starting point and then manually insert the abstract class definitions for each of the Web service operations.

 

Here is how you generate an IDF using wsdl.exe:

 

C:\> wsdl /server /o:StockTraderStub.cs StockTrader.wsdl StockTrader.xsd

 

Here is how you generate an IDF using xsd.exe:

 

C:\> xsd StockTrader.xsd /c

 

Note: To use the wsdl.exe and xsd.exe command-line tools from any directory location on your computer you will probably need to set an environment variable that points to the directory location of the utilities. On my computer I created a user environment variable called PATH with a value of C:\Program Files\Microsoft Visual Studio .NET 2003\SDK\v1.1\BIN. Alternatively, if you are using Visual Studio.NET, then from the Programs menu group you can select Visual Studio.NET Tools | Visual Studio.NET Command Prompt.

 

Implement the Interface Definition in the Web Service (Step 4)

When the interface definitions are in place the last remaining step is to implement them in the Web service code-behind. The first step is to derive the Web service class file from the interface definition, and the second step is to override the abstract methods, as shown in Figure 7.

 

// Step 1 (Before View): Implement the StockTraderStub class

[WebService(Namespace =

 "http://www.bluestonepartners.com/schemas/StockTrader")]

public class StockTraderService : StockTraderStub

{

 // Contains abstract methods (not shown)

}

// Step 2 (After View): Override and implement each of the

  abstract class methods

[WebService(Namespace =

 "http://www.bluestonepartners.com/schemas/StockTrader")]

public class StockTraderService : StockTraderStub

{

public override Quote RequestQuote(string Symbol)

{

// Implementation code goes here

}

}

Figure 7: Derive the Web service .asmx code-behind class from the generated interface definition class (StockTraderStub).

 

You need to set namespace names for both the Web service class and the interface definition classes. I usually include all classes within the same namespace, but there is no rule about this. If you do use different namespaces then in the Web service class file you ll need to import the namespace for the interface definition classes.

 

At this point everything is in place to complete the implementation of the Web service methods. All operations and types are fully described and ready to be referenced from the Web service class file. Figure 8 shows an example implementation of the PlaceTrade Web method, which places a trade order and returns the trade details in a custom object type named Trade.

 

[WebMethod()]

[SoapDocumentMethod(RequestNamespace=

 "http://www.bluestonepartners.com/schemas/StockTrader/",

 ResponseNamespace="http://www.bluestonepartners.com/

 schemas/StockTrader/", Use=SoapBindingUse.Literal,

 ParameterStyle=SoapParameterStyle.Bare)]

[return: XmlElement("Trade", Namespace =

 "http://www.bluestonepartners.com/schemas/StockTrader/")]

public override Trade PlaceTrade(string Account,

 string Symbol, int Shares, System.Double Price,

 TradeType tradeType)

{

Trade t = new Trade();

t.TradeID = System.Guid.NewGuid().ToString();

t.OrderDateTime = DateTime.Now.ToLongDateString();

t.Symbol = Symbol;

t.Shares = Shares;

t.Price = Price;

t.tradeType = tradeType;

// Initialize the Trade to Ordered, using the

  TradeStatus enumeration

t.tradeStatus = TradeStatus.Ordered;

// Code Not Shown: Persist trade details to the database by

  account number and trade ID, or to a message queue

  for later processing

// Code goes here

return t; // Return the Trade object

}

Figure 8: The PlaceTrade Web method.

 

Assuming that you ve followed the steps so far your Visual Studio.NET solution explorer will look like Figure 9.

 


Figure 9: The Visual Studio.NET Solution Explorer showing the StockTrader Web service.

 

Implement the Web Service Consumer (Steps 5 and 6)

The difficult part of the development is done. By now you should have a good understanding of how to approach the development process for message-oriented Web services. Hopefully you now have a better understanding of the variety of moving parts that work together to power a Web service. Visual Studio.NET allows you to take shortcuts in the development process, but you need to avoid temptation and do the manual work that is required to create well documented Web services.

 

We ll close out this article with the final step of hooking the Web service to a client consumer. Figure 10 shows the Visual Studio.NET Solution Explorer as it appears when you add a consumer project to the same solution file as the StockTrader Web service. Note that this is done for convenience, to make debugging the projects simpler. In reality, the Web service and the consumer projects would be located on separate servers and likely in different domains.

 


Figure 10: The Visual Studio.NET Solution Explorer showing the StockTrader Web service and the Web service consumer project.

 

The consumer project contains a proxy class for the Web service that is automatically generated when you add a Web reference from the consumer to the Web service. The proxy class file derives from System.Web.Services.Protocols.SoapHttpClientProtocol, and it provides synchronous and asynchronous invocation mechanisms for each of the Web service operations. It also provides class definitions for the Web service types, just like the interface definition file. The proxy file does not include abstract methods (it only includes implemented methods), so you don t have to implement every method that the proxy class file provides. In addition, the consumer class doesn t need to derive from the service proxy class you simply create instances of the proxy class as needed. (This article does not provide specific instructions for how to create the consumer project, so please refer directly to the code samples that accompany this article.)

 

Figure 11 shows a form-based implementation of the consumer that allows you to receive stock quotes and place trades. Figure 12 shows a sample of the implementation code behind the Get Stock Quote button.


Figure 11: A consumer application for the StockTrader Web service.

 

private void btnQuote_Click(

 object sender, System.EventArgs e)

{

// Create an instance of the Web service proxy

StockTraderProxy serviceProxy =

 new StockTraderProxy();

// Retrieve the Web Service URI from app.config

serviceProxy.Url =

 ConfigurationSettings.AppSettings["remoteHost"];

// Call the Web service to request a quote

Quote q = serviceProxy.RequestQuote(this.txtSymbol.Text);

// Display the Quote results in the form

this.lblCompany.Text = q.Company;

this.lblSymbol.Text = q.Symbol;

this.lblTradeDateTime.Text = q.DateTime;

this.lblLastTrade.Text = q.Last.ToString();

this.lblPreviousClose.Text = q.Previous_Close.ToString();

this.lblChange.Text = q.Change.ToString();

}

Figure 12: Web service consumer code.

 

Notice that the client code references a configuration element called that provides the URI for the StockTrader Web service. It should be entered into the project s web.config file, as shown in Figure 13. This concludes our discussion of how to build a basic message-oriented Web service.

 

Figure 13: The web.config file for the Web service consumer.

 

Conclusion

The purpose of Web services is to exchange and process XML messages, not to act as simple endpoints for remote procedure calls. In this article we studied a six-step process for designing and building a message-oriented Web service from scratch. These steps are:

1)        Design the messages and the data types.

2)        Build the XSD schema file for the data types.

3)        Create a class file of interface definitions for the messages and data types.

4)        Implement the interface in the Web service code-behind file.

5)        Generate a proxy class file (for clients) based on the WSDL.

6)        Implement a Web service client using a proxy class file.

 

The goal of this article is to help you rethink your approach to Web services design so you can start developing the type of message-oriented Web services that fit into a Service Oriented Architecture framework.

 

The sample code referenced in this article is available for download.

 

Jeffrey Hasan is president of Bluestone Partners, Inc., an IT solutions company based in Orange County, CA (http://www.bluestonepartners.com). Jeff is an experienced enterprise architect and .NET developer, is the coauthor of several books and articles on .NET technology, including Performance Tuning and Optimizing ASP.NET Applications (Apress, 2003), and is the author of the upcoming book Expert Service Oriented Architecture in C#: Using the Web Services Enhancements 2.0 (Apress, 2004). Contact Jeff at mailto:[email protected].

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish