Introducing Contract First (Cont.)
Tool Approach to Contract-First
Although tools already exist in the .NET Framework SDK that help you to generate ASMX Web service code from XSD and WSDL, they are not sufficient for effective contract-first work. Developers really need a good WSDL editor or even designer. For the XSD-related part of modeling data and messages you might want to rely on Visual Studio .NET's intrinsic XSD editor.
Let me tell you about a small tool called WSCF (Web services Contract-First) which solves a lot of the problems related to Web services, and it makes the contract-first approach to Web services easier. WSCF is primarily an add-in for Visual Studio .NET, but it also includes a command-line tool. It was designed to make implementing the above-outlined five steps of contract-first Web services as easy and smooth as possible. Therefore, WSCF has two main responsibilities: aid in the design of the data, message and service interface contract description in an interoperable fashion; and generate code from a given service interface description. You'll see how to accomplish this.
In order to get a better impression of what things actually look like and see how they work, I'll walk you through a simple example. Suppose that you're a member of a .NET user group, and you want to make some of the group's member data available to the outside world. You've decided to create a Web service that delivers and accepts data packed in SOAP messages and a client application that talks to this Web service.
Web Service Interface Design in Practice
Your first want to model the metadata for your Web service's interface. You'll design your data and messages with XML Schema and you'll use Visual Studio's XML editor. You'll set up an initial project structure for your Visual Studio .NET solution. You'll name the empty solution UserGroupService and you'll add the projects to it in order to complete the sample.
The first project (named ContractMetadata) is an empty C# project that will just hold all of the original XML metadata files. The second project is a Windows Forms application that implements the Web service consumer (called UGClient). Last but not least, you'll create an empty ASP.NET Web project. This project will be the home of your user group Web service, but you'll start with an empty project. Please refer to Figure 3 to see the initial solution setup.
Figure 3: VS.NET sample solution.
Data and Message Contract
In the very first step you need to start modeling the data that you'll use in the service interface. You'll model the data in XML Schema and in this case it consists of simple and complex types. For the purpose of an integrated development experience you'll stay completely inside the Visual Studio .NET IDE and therefore use its intrinsic XSD editor. Listing 1 shows UgData.xsd, the file that contains the data. You can see one simple and two complex schema types in there. The enumeration DotnetExperience is the simple type, whereas the "structs" UgMember and UgMemberlist represent complex types. For those of you who are not too familiar with XML and XSD: imagine those data structures as an XML-ized variant of Fowler's data transfer objects (DTO).
Next you want to define the messages that you'll exchange through the service interface. Those messages will re-use the data structures modeled in the first step. So technically, this means that your schema file UgMessages.xsd needs an xsd:import statement for the UgData.xsd file.<xs:import schemaLocation="UGData.xsd"
This simple line imports a certain XML namespace into the current document which makes all data types available inside the message schema definition file.
This example uses three messages: RegisterMemberMessage, GetMemberDataRequest, and GetMemberDataResponse (Listing 2). Those messages are just loosely placed inside the schema file and do not yet have any correlation amongst them. If you like, they are just raw messages.
In the third step you'll have to design the actual service interface with its operations. This means you need to map the single messages to operations inside an interface. This phase is obviously the most tedious to complete. Here you won't just use XSD, but rather the quite complex WSDL dialect. Whereas tool support for XSD is extremely good for .NET developers, I haven't found good WSDL editors or designers. This is one of the major reasons why I started to develop and distribute the free WSCF tool. WSCF has a WSDL Wizard component to design the service interface contract of a Web service, as well as enhanced code generation features. Let me now walk you through how to use WSCF to create a WSDL description without having to grok every single detail of this specification or to even handcraft WSDL in Notepad.
In order to get started using the WSDL Wizard you need to add the two existing XSD files for the data and the message types to your contract metadata project. Based on the messages you have designed, you now want to set up the interface. You just have to right-click on the UgMessages.xsd inside your Visual Studio .NET project and select Create WSDL Interface Description... from the context menu (see Figure 4). The WSCF WSDL Wizard opens with a welcome page. On the following page the user has to provide some basic information about the interface including the name, XML namespace and an optional comment. The next page in the wizard allows you to add additional message XML Schema files. Because sometimes you can start right away with one file, but actually have different kinds of message types distributed across several XSD files (see Figure 5).
Figure 4: Starting the WSDL Wizard from a message XSD.
Figure 5: Specifying message schema imports.
Now on to the real meat. Page three of the WSDL Wizard offers a listview component that allows you to add the interface's operations. For your user group scenario you decide to specify two operations named GetMemberData and RegisterNewMember. But this is not enough information to complete this step. There needs to be an explicit configuration of the message exchange pattern (MEP) to employ for each operation. Currently, there are two possible values for the MEP: One-Way and Request/Response. The former expresses that this is a one-shot action, which means you do not want any message sent back to the original sender. The latter indicates that there has to be an answer to the request message (Figure 6). If you are following certain naming patterns for the modeled messages, the wizard will be able to infer the operations from the messages. Just like GetMemberDataRequest and GetMemberDataResponse will result in the GetMemberData operation when using inference.
Figure 6: Declaring the Web service's operations - with operation inference.
You're nearly done. The last important step lets you specify the operation's message parameters. On this page the user simply needs to map the appropriate message from the message XSD files to the message part of each operation. If you were using operation inference in the previous step the wizard has already set the right values here. Optionally, you can also set any number of message headers on this wizard page. Message headers accord to SOAP headers and you can use them to communicate out-of-band data and information like security credentials or transaction IDs (Figure 7). Although there are still some options on the last page of the wizard, you normally do not need them. That's it! Now you should have all the necessary data to actually get the service interface description generated by the tool. When you finish the wizard you have a newly added WSDL file called DotnetUserGroupWebService.wsdl in your project (Figure 8).
Figure 7: Configuring message body and headers.
Figure 8: Generated WSDL in the metadata project.
Speaking of the WSDL, WSCF tries to follow the best practices and rules from the WS-I Basic Profile 1.1. For example, it only generates Document/literal style WSDL and creates one portType per service description (Table 2 lists the features supplied by the wizard). A more thorough look at the generated WSDL (Listing 3) unearths a small but very powerful implementation detail. The message schemas are not embedded in the WSDL but rather just imported.<types>
This approach has several advantages. The most obvious one is reusability and the second most obvious is that it lets you independently work on the message schemas and the interface contract. So you can easily use or re-use already existing schema for your service's messages.
All in all this makes three important metadata files. Both the Web service implementer as well as the client programmer will now need to receive the UGData.xsd, UGMessages.xsd and DotnetUserGroupWebService.wsdl files in order to start their work. You can add all three files to the respective projects for the Web service and the Windows Forms client application. Now you can head into the code generation process.