Design

Place XML Message Design Ahead of Schema Planning to Improve Web Service Interoperability

Yasser Shohoud

This article assumes you're familiar with Visual Studio .NET and XML

Level of Difficulty123

SUMMARY

Web Services are all about exchanging data in the form of XML messages. If you were about to design a database schema, you probably wouldn't let your tool do it for you. You'd hand-tool it yourself to ensure maximum efficiency. In this article, the author maintains that designing a Web Service should be no different. You should know what kind of data will be returned by Web Service requests and use the structure of that data to design the most efficient message format. Here you'll learn how to make that determination and how to build your Web Service around the message structure.

Take Control of Your Data
Messages, not Methods
Formalizing Message Design
Completing the Interface Definition
Implementing the Interface
Programming Against the Interface
Conclusion

When developers build Web Services, they often skip an important first step: design. They begin by adding a Web Service to a project, then add Web methods to that service. While this approach is convenient, it is not a good way to build production Web Services because it ignores the design of Web Service messages. In this article, I will explain why this conventional process is inadequate and show you a better way to build Web Services using Visual Studio® .NET.

Take Control of Your Data

When you build a data-centric application, how do you create the database schema? Do you begin by creating classes and then let your IDE or tools create the database schema for you, or do you design the database schema yourself, taking into account normalization, referential integrity, and performance optimizations? Chances are you design and create the database schema yourself. Even if you use a visual schema designer rather than data definition language (DDL) statements, you are still taking control of the database schema design.

Web Services are all about supplying the right data at the right time. When a client calls a Web Service, an XML data message is sent over the wire and a response is returned to the client. When you program the Web Service and its clients, you are really programming against these messages. The data in these messages is ultimately what the application cares about. So why would you create a Web Service beginning with the classes and methods and let the tools create the message schemas for you? You should design the data (message) schema and implement the Web Service to fit this design, like you would when designing a database schema.

Messages, not Methods

Thinking in terms of messages rather than methods is a bit of a shift. Consider, for example, a simple Web Service operation that receives a ZIP code and returns the current weather conditions. Coming from an object-oriented world, you'd be tempted to design a method named GetWeather that takes a string argument and returns an instance of CurrentWeather (see Figure 1).

[WebMethod] public CurrentWeather GetWeather(string ZipCode) { CurrentWeather cw=new CurrentWeather(); //get the current weather information //then return it return cw; } public class CurrentWeather { //this is the temperature in Fahrenheit private float _Temperature; //these are public fields public string Conditions; public string IconUrl; public Single Humidity; public Single Barometer; //temperature is implemented as a property public float FahrenheitTemperature { get { return _Temperature; } set { _Temperature=value; } } public float CelsiusTemperature { get { return (_Temperature - 32) * 5/9; } } }

This approach is flawed because you are designing methods and types that are only meaningful within the Web Service itself. Your Web Service client will not necessarily know anything about your CurrentWeather class, such as what its members represent. In fact, the client only knows that it receives an XML schema (XSD) complex type called CurrentWeather. This XSD type definition is automatically created for you when you navigate to the Web Service's WSDL document (for example, weatherservice.asmx?wsdl). It is up to the client tools to map this XSD type to whatever data structure makes sense on the client side. For example, the SOAP Toolkit would present instances of CurrentWeather as an XML node list, IXMLDOMNodeList interface. The .NET Framework is particularly good at translating XSD types to native types, which can cause plenty of grief. For example, a .NET client that adds a Web reference to the weather service in Figure 1 would get a class named CurrentWeather, which is a translation of the CurrentWeather XSD type: public class CurrentWeather { public string Conditions; public string IconUrl; public Single Humidity; public Single Barometer; public float FahrenheitTemperature; }

For someone who doesn't understand what Web Services are really about, the first question would be "What happened to my CelsiusTemperature property and why is FahrenheitTemperature a field rather than a property?" The answer is that only public, read/write members of the service's CurrentWeather class are serialized to XML by the .NET Framework XML Serializer. Since CelsiusTemperature is read-only, it is not serialized and doesn't show up at all in the client's CurrentWeather class. Furthermore, the auto-generated client class always contains public fields rather than property procedures. Again, the client only knows about an XSD type named CurrentWeather. This XSD type makes no distinction between property procedures and fields; to the client, it's all data.

At this point you might be thinking that Web Services have severe limitations because a client can't really get an instance of the same object that the service returns. This is not a limitation of Web Services per se, but an example of why it's wrong to view Web Services as a way to access remote objects (much like DCOM is).

The best approach for designing the weather service is to begin by defining your messages. For example, you define a WeatherRequest message that includes the ZIP code and a CurrentWeather message that includes current weather information. Figure 2 shows example request and response messages, which should serve as the starting point in your Web Service design.

20171 Sunny https://www.LearnXmlws.com/images/sunny.gif 0.41 30.18 75 23.89

Since Web Service and client developers are armed with the understanding that your Web Service will receive a WeatherRequest message and return a CurrentWeather message, they will not be confused by implementation details such as read-only members and property procedures.

Formalizing Message Design

Now that you've created example request and response messages, you need to formalize the design of those messages so that development tools such as Visual Studio .NET can read this design and provide a rich development experience such as client proxy generation.

To formalize message design you need to create an XML schema describing your request and response messages. While you can create this schema using any schema or text editor, I prefer to use the Visual Studio XML Schema editor.

To use the schema designer, start Visual Studio and choose New File | XML Schema. The designer comes with a specialized toolbox that contains schema constructs such as element declarations and type definitions. To declare an element such as WeatherRequest, simply drag the Element icon from the toolbox and drop it onto the designer's surface. Each element has two main attributes that you need to set: the element's name and its data type. When you're setting the element's data type, you get to choose from a list of XSD built-in types or define your own types. For example, WeatherRequest is of the built-in type string (the WeatherRequest element contains a string), whereas CurrentWeather is of a new custom type that contains other elements.

The concept of defining types, then declaring elements of those types, is quite similar to what you already do in your favorite programming language: you define classes, such as the CurrentWeather class, which then become a new type within your project. You then declare variables of this class, such as the cw variable shown in Figure 1.

The schema designer makes it easy to define the new CurrentWeather type by simply populating rows in CurrentWeather element's box. As you can see, Figure 3 shows the CurrentWeather element with an anonymous (or unnamed) type that contains Conditions, IconUrl, Humidity, Barometer, FahrenheitTemperature, and CelsiusTemperature.

Figure 3** Visual Studio XML Schema Designer **

There's one last step before you are finished with message design. You must set the targetNamespace property of the XML Schema to some namespace that uniquely identifies your Web Service or your application, as shown in the properties window in Figure 3. This is a very good practice, but it is not absolutely required, which means that developers are more likely to overlook this important step.

If for some reason you need to get to the XML Schema itself, you can simply switch to XML view by clicking on the XML tab shown at the bottom of Figure 3. This brings up the entire schema in an XML editor where you can modify it to meet your particular requirements, as shown in Figure 4.

Completing the Interface Definition

The XML schema shown in Figure 4 adequately describes the data contained in the request and response message, but there are still more aspects of the messages that need to be described in a formal, machine-readable form. For example, are the messages using SOAP remote procedure calls or document styles? How is the data encoded on the wire? Is it using SOAP Section 5 or literal encoding? To provide this information, you create a Web Services Description Language (WSDL) document. There is currently no WSDL designer built into Visual Studio .NET, but there are a few third-party products that provide GUI WSDL designers. Furthermore, WSDL is an XML grammar, so you can use any XML or text editor to create WSDL documents. The WSDL grammar can be a bit involved because of the myriad features that WSDL attempts to provide. Practically, however, you only use a small subset of those features so you can start with a boilerplate WSDL template document like the one in Figure 5 and customize it to meet your needs.

Figure 6 shows the template WSDL document customized for the Weather interface. I changed the part information within the request and response message to point to the WeatherRequest and CurrentWeather elements that I defined in the ServiceMessages schema. I also named the operation GetWeather and the binding WeatherInterface. These names will show up in your code as the Web method name and the binding name, respectively, so it is best to create more distinctive names.

This completes the design phase. You now have a formal definition of the Web Service's interface, including a definition of the application data contained in each request and response message. The next steps are for the service developer to begin implementing this interface and the client developer to begin programming against it. Please keep in mind that the client developer need not wait until the service is implemented to begin building the client. This means that you can save time by allowing client and service development to proceed in parallel.

Implementing the Interface

To implement a Web Service interface, you use a Microsoft® .NET Framework SDK tool named wsdl.exe. This command-line tool operates on WSDL documents and can generate a Web Service stub class (a class that implements the given interface) or a Web Service proxy class (to be used by clients).

For example, in order to generate a stub implementation of the Weather service interface, you run wsdl.exe with the /server switch, passing it the interface's WSDL URL, as shown here: C:\> wsdl.exe /server /o:WeatherStub.cs https://localhost/MSDNMag/weatherinterface.wsdl Microsoft (R) Web Services Description Language Utility [Microsoft (R) .NET Framework, Version 1.0.3705.0] Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. Writing file 'WeatherStub.cs'. By default, wsdl.exe generates the output in C#, but you can use the /language switch to choose Visual Basic® .NET or JavaScript. In this example, the generated file, WeatherStub.cs, contains an abstract class named WeatherInterface that implements the Weather interface. This class contains one method named GetWeather, which takes in a string and returns an instance of CurrentWeather. CurrentWeather is another class that was generated based on the CurrentWeather type defined in the XML schema.

To begin implementing the service code, you add this WeatherInterface class to your project, create a new Web Service, and then change the Web Service so that it inherits from the WeatherInterface abstract class. You then override the GetWeather method of the base class and place your implementation logic there, as shown in Figure 7. To expose GetWeather via SOAP, you'll need to add a WebMethod attribute. To make GetWeather a true implementation of the GetWeather operation defined earlier in WeatherInterface.wsdl, you'll also need to add an XmlElement to the return value and add a SoapDocumentMethod attribute, setting its ParameterStyle property to SoapParameterStyle.Bare (see Figure 7).

using System; using System.Web.Services; using System.Web.Services.Protocols; namespace MSDNMag { [WebService(Namespace = "https://learnxmlws.com/WeatherService")] public class WeatherService : WeatherInterface { public WeatherService() { } [WebMethod] [SoapDocumentMethod("", ParameterStyle= SoapParameterStyle.Bare)] [return: XmlElement ( "CurrentWeather", Namespace="https://learnxmlws.com/Weather")] public override CurrentWeather GetWeather(string WeatherRequest) { CurrentWeather cw=new CurrentWeather(); //put code here to get the weather ... return cw; } } }

If you're developing in Visual Basic .NET, you don't need to manually add these attributes. Visual Studio adds them to your code automatically when you select the GetWeather method from the overrides menu.

If you build this Web Service and then navigate to its auto-generated WSDL document, you'll see it contains quite a bit of information. This is actually a problem. First, the WSDL document contains a complete copy of WeatherInterface. Next, the document also contains two other interfaces that support the HTTP GET and HTTP POST protocols.

Having a copy of the interface defeats the purpose of having a single interface definition that can be implemented several times. So the first thing you need to do is remove this copy of the interface from the service's WSDL and somehow make it reference the WeatherInterface.wsdl document that you created earlier. To do this, you need to add a WebServiceBinding attribute to the Web Service itself, indicating the name of the WSDL binding (the WeatherInterface binding) that the service implements, as well as the URL of the WSDL document in which that binding is defined. You also have to set the binding property of the SoapDocumentMethod attribute on each Web method to indicate that the Web method implements a specific operation defined in that binding. Figure 8 shows the Web Service with these modifications.

using System; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml.Serialization; namespace MSDNMag { [WebService(Namespace = "https://learnxmlws.com/WeatherService")] [WebServiceBinding(Name="WeatherInterface", Namespace="https://learnxmlws.com/Weather", Location= "https://localhost/MSDNMag/WeatherInterface.wsdl")] public class WeatherService : WeatherInterface { public WeatherService() { } [WebMethod] [SoapDocumentMethod("", Binding="WeatherInterface", ParameterStyle=SoapParameterStyle.Bare)] [return: XmlElement("CurrentWeather", Namespace="https://learnxmlws.com/Weather")] public override CurrentWeather GetWeather(string WeatherRequest) { CurrentWeather cw=new CurrentWeather(); //put code here to get the weather ... return cw; } } }

Finally, I recommend that you turn off the HTTP GET and HTTP POST bindings in your service's WSDL document. To disable these protocols for a specific application, you simply edit your application's web.config file and then add a webServices section inside system.web, like so: You can also disable these protocols for the entire machine by editing machine.config and removing HttpGet and HttpPost from the list of protocols.

Now when you build your Web Service and navigate to its WSDL document, you get a lightweight document that simply imports WeatherInterface.wsdl and adds a service definition (see Figure 9). Think of the service definition as a specific implementation of the interface defined in WeatherInterface.wsdl.

Programming Against the Interface

To program clients that utilize the Weather interface, you can use wsdl.exe or Add Web Reference in Visual Studio to generate a proxy class from the interface. Note that when you generate this class, you'll point to WeatherInterface.wsdl, which contains interface-only information. Specifically, it does not contain a URL of a service that implements that interface. Therefore, the client must set this URL either at design time or run time. Instead of hardcoding the URL in your client code, you're better off placing this URL in your client's config file and reading it at run time. Here is a client programmed against WeatherInterface: Private Sub btnWeather_Click( _ ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnWeather.Click Dim ws As New localhost.WeatherInterface() ws.Url = System.Configuration. _ ConfigurationSettings.AppSettings("ServiceUrl") Dim cw As localhost.CurrentWeather = _ ws.GetWeather("20171") End Sub

Conclusion

Web Services are all about applications exchanging data over the Web in the form of XML messages, so building a Web Service requires careful design of these messages using XML Schema and WSDL. When you begin with message design rather than method design the kind of data your Web Service expects to receive and return is made clear. By designing messages using XSD and WSDL, you create a formal interface definition that Web Service developers can implement and client developers can program against simultaneously. Next time you begin a Web Service project, begin by designing the messages format using the Visual Studio XML Schema designer.

For related articles see:
The XML Files: A Quick Guide to XML Schema
The XML Files: A Quick Guide to XML Schema - Part 2
House of Web Services: The Continuing Challenges of XML Web Services

For background information see:
Real World XML Web Services: For VB and VB .NET Developersby Yasser Shohoud (Addison-Wesley, 2002)
XML Web Services Basics

Yasser Shohoudis a program manager on the Microsoft XML Messaging Team. He is the author of Real World XML Web Services (Addison-Wesley, 2002).