WSCF 0.6 UnveiledSchema-based Contract-First Design and Development of Web Services on
Today's .NET Platform
|
| Project | Type | Description |
| ContractMetadata | C# Empty Project | Contains the metadata definitions for data, messages, and interfaces |
| RestaurantService | C# Empty Web Site (File system based) | Restaurant Web service implementation |
| RestaurantClient | C# Console Application | Restaurant Web service client implementation |
It is important to note that we do not add a typical ASP.NET Web Service project to our solution, but rather a C# Empty Web Site. This is obvious as we want to omit the automatic and template driven code generation of our Web service code in the first place. Instead, we want to take the contract-first route.
If all three projects are added to the solution, your Solution Explorer window might look like the following figure/ screenshot:

Figure 2: Sample VS 2005 solution with empty projects

Figure 3: Data structures for Restaurant sample
As stated in the previous section, our service allows administrators to add new restaurants to the service. However, we want to allow access only to administrators we trust. Therefore it would be necessary for RestaurantService administrators to submit their credentials for authentication before adding a new restaurant. We want to use SOAP headers to transport the authentication credentials (hopefully over an SSL connection J). Thus we need another data structure to carry our user credentials. Since we want to separate the data structures used in the SOAP Headers from the ones used in the SOAP Body, lets define the user credentials in a new XSD file called RestaurantHeaderData.xsd.
Figure 4: Header data for Restaurant sample
Figure 5: Messages for the Restaurant sample
Figure 6: Illustration of the schema import mechanism for the data structures
WSCF comes with its own WSDL generation wizard that tries to hide any suspicious details of the WSDL specification from the developer or architect. This wizard allows you to do all your interface contract creation work just inside the Visual Studio 2005 IDE. It hides all the complex details of the specification and generates a WSDL document, which is totally compliant with the interoperability recommendations of WSI BP (Basic Profile) 1.1.
WSCF also allows the user to import multiple schema files to create a WSDL document. Not only that, it also provides a feature to automatically infer operations from your message schema definition. This saves a lot of time you might otherwise spend manually adding operations, even though they could be guessed from the message names.
The following table shows the currently supported string patterns for operation inference.
| Input Message Name Element | Output Message Name Element | Inferred Operation Name |
| XYZ | XYZResponse | XYZ |
| XYZRequest | XYZResponse | XYZ |
| XYZRequestMessage | XYZResponseMessage | XYZ |
The latest version of WSCF (version 0.6) also armed with a feature which you can preferably use to generate the SOAP 1.2 binding. Last but not least, the wizard enables a simple kind of WSDL round-tripping, which means you can generate a WSDL, review it, and later modify it using the wizard. Lets take a look at how the WSDL wizard generates the interface contract for the RestaurantService.
To start the WSDL wizard right click on your messages schema file (RestaurantMessages.xsd in this case) in the Visual Studio Solution Explorer and select the Create WSDL Interface Description menu item from the context menu.
Figure 7: Starting the Web service interface design Step
The wizard starts with a welcome message. Click on the Next button to collect some basic metadata for our Web service description. This includes the service name, the Web services XML namespace and an optional description.
Figure 8: Collecting basic metadata for the Web service interface description
The next step allows you to import additional schema files into the WSDL. In our example we have to import the schema file with the type definitions for our message headers, RestaurantHeaderData.xsd. Its important to keep in mind that you cannot import two schema files which have the same target namespace.
Figure 9: Specifying additional XML schema imports
In step 3 you define the operations in your contract the meat of this process. However, WSCFs WSDL wizard is intelligent enough to infer the operations according to message name patterns in your message schemas. Click on the Infer Operations checkbox to automatically infer the operations.
Figure 10: Using operation inference
The following step allows you to optionally configure inbound and outbound messages in your operations. In this step you can select the message element for your message body from the schema. However, if you inferred the service operations, message body elements are automatically and hopefully correctly - configured for you. Optionally you can customize the name for your inbound/outbound message.
Figure 11: Specifying messages and optional properties
The most interesting feature on Step 4 is the Message headers checkbox. When you check that box, you can select schema types for one or more message headers for your inbound/outbound messages from the drop-down underneath the checkbox. In this case we create a message header for addRestaurantIn inbound message to carry our user credentials. Check the Message headers checkbox and select Credentials from the dropdown.
Figure 12: Specifying message headers
In the next step you can select whether you want to have the <service> tag in your WSDL. <service> allows you to specify a default location of a Web service that implements the abstract interface you are currently modeling. Also, you can select whether you want to start the code generation immediately after the wizard finishes. The WSDL specification defines <service> as optional, but some Web services frameworks dont work correctly unless the <service> element is present in the WSDL document. In addition to the above features WSCF 0.6+ versions give you an option to generate the SOAP 1.2 binding in the generated WSDL.

Figure 13: Specifying additional options
Step number 6 allows you to modify the relative paths of your imported schema files. This may be needed if you have the real XSD files (e.g. for production use) at a different location, e.g. at a URL on a web server.

Figure 14: Changing the paths to the XSDs
Click the Finish button on the last screen and you will see the generated WSDL file in your solution explorer. Voila.

Figure 15: Generated WSDL inside the metadata project

Figure 16: Deploying the Web service's metadata to the developers
Figure 17: Generating code for the service side
This action will bring up the code generation options dialog box which allows you to control the code generation.

Figure 18: Code generation options for the Web service
Since we generate the code for the service, we select the Service-side stub radio button. Various checkboxes in the Options group box let you generate the code according to what you actually need. We will take a look at each of those options in a moment. Now it is important to notice that some options are available for both client-side and service-side code generation, whereas some others are only available for client-side or service-side.
public class RestaurantInfo { public string Name; }Listing 1: Public fields in data transfer object
public class RestaurantInfo { private string name; public string Name { get { return this.name; } set { if ((this.name != value)) { this.name = value; } } } }Listing 2: Private fields and get/set properties in data transfer objects
[Serializable()] public class RestaurantInfo { // }Listing 3: Serializable data transfer objects
// Collection type generated. public class RestaurantInfoCollection : System.Collections.CollectionBase { } public class GetRestaurantsResponse { // Array declaration is modified to use the newly created // collection type. public RestaurantInfoCollection restaurants; }Listing 5: List-like data in generated collection types
public System.Collections.Generic.List<RestaurantInfo> restaurants;
Listing 6: List<T> type collection generation
public partial class RestaurantInfo :Listing 7: Data binding option will generate the INotifyPropertyChanged implementation
object, System.ComponentModel.INotifyPropertyChanged { public int RestaurantID { get { return this.restaurantID; } set { if ((this.restaurantID != value)) { this.restaurantID = value; this.RaisePropertyChanged("RestaurantID"); } } } }
[System.Xml.Serialization.XmlElementAttribute(Order=0, ElementName="restaurantID")]Listing 8: Order identifier generation
public int RestaurantID; [System.Xml.Serialization.XmlElementAttribute(Order=1, ElementName="name")] public string Name;
<xs:complexType name="restaurantInfo"> <xs:sequence> <xs:element name="restaurantID" type="xs:int" /> <xs:element name="name" type="xs:string" /> </xs:sequence> </xs:complexType> public partial class RestaurantInfo { public int RestaurantID; public string Name; }Listing 9: Casing adjustments
public System.DateTime OpenFrom { get { return this.openFrom; } set { if ((this.openFrom != value)) { this.openFrom = value; this.RaisePropertyChanged("OpenFrom"); this.openFromSpecified = true; } } }Listing 10: Automatic specified handling
WSCF 0.6 version also introduces a feature to expose your modeled WSDL via the .asmx endpoint. This will allow the users to view the modeled WSDL by passing ?wsdl parameter to the .asmx endpoint. You can turn on this feature by selecting the Enable WSDL check box in the code generation dialog box. (Please see the Enabling WSDL section below for a discussion about a minor design issue in this feature)
There is one more option we did not discuss yet (Old async code). We will be looking at it in the next section because it is relevant for the client side code generation. So, according to the options selected for service-side code generation our solution explorer will look something like the following picture.

Figure 19: Generated code for the service side
Last but not least, we can specify the desired names for the ASMX file and the .NET code namespace for the generated code by using the Service filename and Service namespace textboxes, respectively.
We start generating the code for the client side by selecting the code generation option for the RestaurantService.wsdl file in the RestaurantClient project.

Figure 20: Starting up code generation for the client side
This action will bring up the same code generation dialog box we saw earlier when generating the code for the service side. However, this time we are going to select the Client-side proxy radio button in the General group box.

Figure 21: Code generation options for the client
The behavior of the common options is the same as described in the service-side code generation section. We also have two additional options for proxy code generation. Configure endpoint option will generate an entry in the app.config or web.config file to configure the services communication endpoint URL.
Optionally we can select the Access messages option and access the SOAP messages we exchange with the service through read-only properties on the proxy class.
By default, the proxy code generation uses the new event-based asynchronous pattern in the generated code (For more information please see this link). However, WSCF also has an option to specify whether you want to follow the old asynchronous programming pattern or not (Delegate-based asynchronous pattern).
We can specify the proxy filename and the namespace name for the generated code by using Proxy filename and Proxy namespace textboxes respectively.
Finally hitting the Generate button will output the code and our Solution Explorer will look something like the following picture.

Figure 22: Generated code for the Web service client
It is also interesting to notice that WSCF will generate a new task in the Task List to remind you to configure your actual Web service endpoint.

Figure 23: Task indicating to check the Web service's endpoint in config
Now that we have the skeleton for our code we can continue with our actual service and client implementations. Essentially the service developer will open the code behind file of the .asmx file (RestaurantService.asmx.cs in this case) and implement each of the methods which throw a NotImplementedException. The developer of the client side will instantiate an instance of the proxy class and call its methods in order to communicate with the service. Please download the Visual Studio 2005 solution for the complete implementation.
It is quite obvious that nobody in the world will create a 100% accurate contract at the first time. WSCF comes with WSDL round-tripping feature which allows you to modify your existing contracts with the minimum effort. Please note that we are not talking about modifying a published and released contract but rather working in an iterative fashion on one instance of a WSDL-based interface description during development.
Lets take a look at how we can use this feature in our application. Lets start adding a new simple data type to resemble the newly introduced rating information into the RestaurantData.xsd file in the ContractMetadata project.

Figure 24: Adding a rating data structure to the metadata
Now we have to change our message schema as well and define a new message to exchange our RatingInfo data.

Figure 25: Updated messages schema for rating restaurants
Our next step is to add a new operation to our interface contract. Again, we do not want to hand-craft the WSDL. This time we use the WSDL round-tripping feature to alter our existing RestaurantService.wsdl file. We can start round-tripping by right clicking and selecting the Edit WSDL Interface Description menu item from the context menu.

Figure 26: Starting up WSDL round-tripping
This brings up the same WSDL wizard we used to create our original service description with. However, this time it is pre-populated with the values from the RestaurantService.wsdl file. When we select the Infer Operations checkbox in step 3 we can see a newly added operation called rateRestaurant in our operations list.

Figure 27: Interface with update operations list
In step 5 the WSDL wizard forces you to generate the code because if doing any changes in the WSDL means you really should regenerate the code. However, in this case we just omit the code generation as we modify the contract inside the ContractMetadata project.
Now that we have our modified contract we must copy it to the RestaurantService and RestaurantClient projects, respectively. We generate the code for each project like we did in the previous sections. However this time we can select the Overwrite existing files option, while generating code for both client side and service side. This will replace the existing files by the newly generated files. Otherwise the code generation will automatically produce unique file names to preserve your existing code.

Figure 28: Overwriting existing code files while generating code
In our demo application walkthrough we saw how straight-forward it is to build our web services with WSCF in a contract-first way. However, in this section we are going to show you some more interesting things that WSCF code generation does for you.
If you take a look at the generated code for our restaurant service application, you will see that the code generation generates a CLR interface for our web service interface. Developers can use this interface and implement it in various layers in their application. For instance, one can take this interface and implement it in an Enterprise Services component which handles the business logic for the restaurant service.
public interface IRestaurantServicePort { GetRestaurantsResponse GetRestaurants( GetRestaurants getRestaurants1); void AddRestaurant(AddRestaurant addRestaurant1); }Listing 11: Generated CLR interface
Generated code for the service side automatically adds a statement to throw a NotImplementedException from all WebMethods. This ensures that the code compiles successfully and also complies with the .NET Framework design guidelines.
public virtual GetRestaurantsResponse GetRestaurants(Listing 12: NotImplementedExceptions in WebMethods
[System.Xml.Serialization.XmlElementAttribute("getRestaurants",
Namespace= "urn:thinktecture-com:demos:restaurantservice:messages:v1")]
GetRestaurants getRestaurants1) { throw new System.NotImplementedException(); }
In WSCF 0.5+ versions, the service-side code generation now creates a modified ASMX documentation page. It avoids viewing the WSDL by using wsdl parameter in the URL by returning an HTTP 404 error.
As mentioned above, WSCF allows you to expose the modeled WSDL via the ASMX endpoint. However, we came across a minor problem which we had to leave it as it is in our RTM.
When Enable WSDL option is turned on, our modeled WSDL is imported into an ASMX generated WSDL (See the highlighted code in blue color in listing 13). This ASMX generated WSDL defines the two <wsdl:port> elements to expose the SOAP 1.1 and SOAP 1.2 bindings.
<?xml version="1.0" encoding="utf-8"?> <wsdl:definitions> <wsdl:import namespace="urn:thinktecture-com:demos:restaurantservice:webservice:v1" location="Contract/RestaurantService.wsdl" /> <wsdl:types /> <wsdl:service name="RestaurantServicePort"> <wsdl:port name="RestaurantService" binding="tns:RestaurantService"> <soap:address location="http://localhost:1633/RestaurantService/RestaurantService.asmx" /> </wsdl:port> <wsdl:port name="RestaurantService1" binding="tns:RestaurantService"> <soap12:addres location="http://localhost:1633/RestaurantService/RestaurantService.asmx" /> </wsdl:port> </wsdl:service> </wsdl:definitions>Listing 13: ASMX generated WSDL
However, due to the design of ASMX runtime the <wsdl:port> generated for SOAP 1.2 is pointing to the same binding as the SOAP 1.1 (take a look at the code highlighted in red color above). Therefore when we generate the sample SOAP 1.2 message in the operation help page; we look for the <wsdl:port> element for the actual SOAP 1.2 binding and if it is not available we leave the SOAP address and the host fields blank.
For example for the above service, the correct sample SOAP 1.2 message should look like:
POST /RestaurantService/RestaurantService.asmx HTTP/1.1 Host: localhost Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope> </soap12:Envelope>Listing 14
Since we do not have the wsdl:port element, the generated sample message would actually look like:
POST [SOAP address not available] HTTP/1.1 Host: [Host not available] Content-Type: application/soap+xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap12:Envelope> </soap12:Envelope>Listing 15
WSCF is also offering a command line interface to the code generation engine (wscf.exe). All code generation can thus be included in your batch scripts and/or build process. The following screenshot shows all available options of wscf.exe.
Figure 29: wscf.exe command line tool parameters (click on the image
to enlarge)
Well, not everybody will buy the schema-based contract-first approach. This is fine. This is what we expect. But we surely know out of our own experience and from customers feedback so far: Yes! This is what we are doing since years and WSCF just makes it a bit easier.
Thanks.
For feedback, please send email to the WSCF team at thinktecture.