The XML Files

What's New in WSE 2.0

Aaron Skonnard

Contents

Compatibility
Side by Side Execution
Installation
Getting Started with 2.0
Messaging Enhancements
WSDL Support
Security Enhancements
WSE Security Settings Tool
Automatic Secure Conversation
Next-Hop Routing
Where are We?

Microsoft has recently released Web Services Enhancements for Microsoft® .NET (WSE) 2.0. WSE 2.0 provides extensions to the existing ASP.NET Web services framework (.asmx) as well as a standalone messaging framework that's completely transport independent. The WSE 2.0 Technology Preview release has been available on the MSDN® Web site for some time but this new release contains several interesting additions and changes worth highlighting.

Compatibility

WSE provides a shipping vehicle for introducing new Web services functionality in a timely fashion. This makes it possible for Microsoft to keep up with emerging Web services specifications that are continually changing. Since WSE serves as a platform extension, it wasn't designed under the same constraints that apply to a major platform release. This means WSE doesn't have to play by the same rules as, say, a new release of the .NET Framework where breaking changes would be disastrous.

According to the documentation, "WSE attempts to maintain a degree of compatibility" but it acknowledges that complete compatibility won't be possible given the nature of certain changes. For example, sending a SOAP message between an application built with WSE 1.0 and another application built with WSE 2.0 will always result in a SOAP fault. This is because each version implements a different set of Web services specifications. WSE 1.0 implements WS-Routing and the original WS-Security specifications, while WSE 2.0 implements WS-Addressing and the new OASIS WS-Security standard.

There may also be code incompatibilities when moving between WSE versions. The development team made several breaking changes to the WSE object model between versions 1.0 and 2.0. This means you'll have to rework some existing WSE 1.0 code to work with the new WSE 2.0 object model.

WSE 2.0 uses a different assembly and namespace name than WSE 1.0. The WSE 1.0 assembly name is Microsoft.Web.Services, while the WSE 2.0 assembly name is now Microsoft.Web.Services2. The name of the WSE 2.0 configuration element is now <microsoft.web.services2>, and the WSE 2.0 root namespace is now microsoft.web.services2 (see Figure 1).

Figure 1 Differences Between WSE 1.0 and WSE 2.0

Item WSE 1.0 WSE 2.0
Assembly name Microsoft.Web.Services Microsoft.Web.Services2
Namespace name Microsoft.Web.Services Microsoft.Web.Services2
Configuration element <microsoft.web.services> <microsoft.web.services2>
Version number 1.0.0.0 2.0.0.0
PublicKeyToken 31bf3856ad364e35 31bf3856ad364e35

These differences will affect WSE-related entries in your application configuration files or project references as well as your code wherever you're using the WSE namespace. For example, in WSE 1.0 you register the WSE SoapExtension as shown in the top of Figure 2, whereas in WSE 2.0 you register the SoapExtension as shown in the bottom of Figure 2.

Figure 2 Registering the WSE SoapExtension

WSE 1.0

<configuration> <system.web> <webServices> <soapExtensionTypes> <add type= "Microsoft.Web.Services.WebServicesExtension, Microsoft.Web.Services, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" /> </soapExtensionTypes> </webServices> <system.web> <configuration>

WSE 2.0

<configuration> <system.web> <webServices> <soapExtensionTypes> <add type= "Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" /> </soapExtensionTypes> </webServices> <system.web> <configuration>

Another fundamental change in the core object model has to do with acquiring SoapContext objects in your code. WSE 1.0 introduced the SoapContext class that models WSE information passed in the SOAP message (similar to the HttpContext object for generic HTTP requests). In WSE 1.0, you access the current SoapContext object from within a WebMethod as shown in the code located at the top of Figure 3.

Figure 3 Get Current SoapContext Object

WSE 1.0

using Microsoft.Web.Services; // WSE 1.0 public class SomeClass { [WebMethod] public string DoSomething() { SoapContext reqCtx = HttpSoapContext.RequestContext; SoapContext resCtx = HttpSoapContext.ResponseContext; ... // use SoapContext to access WSE information } ••• }

WSE 2.0

using Microsoft.Web.Services2; // WSE 2.0 public class SomeClass { [WebMethod] public string DoSomething() { SoapContext reqCtx = RequestSoapContext.Current; SoapContext resCtx = ResponseSoapContext.Current; ... // use SoapContext to access WSE information } ••• }

In WSE 2.0, however, the HttpSoapContext class has been marked obsolete because the object model has evolved to the point that SoapContext can be used over other protocols in addition to HTTP. Hence, in WSE 2.0 HttpSoapContext has been removed and two new classes named RequestSoapContext and ResponseSoapContext have been added. Each class has a static Current property for retrieving the current SoapContext object as shown in the bottom of Figure 3.

Several other WSE 1.0 classes have been changed or entirely removed. For example, on the security front, the IPasswordProvider and IDecryptionKeyProvider interfaces have been removed in WSE 2.0. You'll have to rework any WSE 1.0 applications that used them and port the code to the new WSE 2.0 security framework. These are the most fundamental and obvious breaking changes but there are others as well. We'll discuss these differences throughout the remainder of this column.

In order to make it easier for developers to migrate to WSE 2.0, Microsoft also made it possible to run both Web Services Enhancements versions side by side.

Side by Side Execution

If you can't afford to break existing services or deal with the compatibility issues just described, you can choose to run both WSE versions simultaneously. Thanks to the fact that WSE 2.0 uses different assembly, namespace, and configuration names, you can run WSE 1.0 and WSE 2.0 applications side by side on the same machine and even in the same process. In fact, it shouldn't cause any problems to install WSE 2.0 on a machine where WSE 1.0 services are currently deployed. The WSE 1.0 services will continue to use the WSE 1.0 bits and new services can be designed to take advantage of the newly installed WSE 2.0 bits.

However, you should be aware that a given Web service cannot use WSE 1.0 and WSE 2.0 SoapExtensions at the same time. It can only be configured to use one or the other. Client applications, on the other hand, can use a mix of WSE 1.0 and WSE 2.0 proxy classes by distinguishing between them by using fully qualified names. And you can use the WSE 2.0 messaging API together with WSE 1.0 SoapExtensions.

Installation

In order to get started with WSE 2.0, download the bits from the MSDN Web Services Developer Center and run the installation. If you have the WSE 2.0 Technology Preview installed, you must uninstall it before installing this release. However, as we discussed in the previous section, you don't have to uninstall WSE 1.0 before moving forward with WSE 2.0 since they can coexist.

When you run the installation, you'll notice several setup type options that didn't exist before, including options to install only the runtime files, runtime plus tools, documentation, Visual Studio tools, and a custom install option. These setup options help distinguish between the various WSE components needed by different usage profiles, and the Custom option lets you select the various components manually. Most developers should choose the Visual Studio® Developer option, which installs the WSE 2.0 runtime files, documentation and samples, standalone tools, and the Visual Studio .NET tools.

WSE 1.0 didn't ship with any supported tools. Microsoft provided the WSE Settings tool as a separate download from the MSDN Web site; it came with its own installation program and wasn't considered part of the supported product. Now WSE 2.0 comes with a fully integrated tool that greatly simplifies the overall development process.

Getting Started with 2.0

Assuming you choose the Visual Studio Developer option, you can begin integrating WSE 2.0 with your Visual Studio .NET solutions. Getting things configured properly is as easy as running the WSE Settings tool and checking a few boxes. You open the WSE Settings Tool by right-clicking on your project icon in Solution Explorer and selecting WSE Settings 2.0.

This will open a multi-tab dialog, which is referred to as the WSE settings tool. This tool gives you a user-friendly interface to the various WSE 2.0 configuration settings. Most of your interactions with the dialog will simply make changes to the <microsoft.web.services2> section of the application configuration file. You can always make these changes by hand, but the tool makes it easier to get it done right and to get it done quickly. Browsing through the various tabs will give you a quick overview of the new features provided in this release.

You can configure your project to use WSE 2.0 by clicking "Enable the Project for Web Services Enhancements" on the General tab. Checking this box causes the tool to add a reference to Microsoft.Web.Services2.dll and it adds the <microsoft.web.services2> section to the application configuration file. It also causes Visual Studio .NET to create WSE-enabled proxy classes when creating new Web references.

You can also check "Enable Microsoft Web Services Enhancement Soap Extensions" to add the WSE SoapExtension mapping to the project's web.config file (this only applies to ASP.NET projects). You'll want to do this if you're planning to use WSE 2.0 to extend the functionality of an ASP.NET Web Services project, such as by adding WS-Security support to a set of WebMethods. After checking both boxes and pressing OK, your project should now contain the WSE 2.0 assembly (see Figure 4) and the web.config file should look like Figure 5.

Figure 5 web.config File

<configuration> <configSections> <!-- this registers the WSE2 configuration section --> <section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> </configSections> <system.web> <webServices> <soapExtensionTypes> <!-- this configures the WSE2 SoapExtension --> <add type="Microsoft.Web.Services2.WebServicesExtension, Microsoft.Web.Services2, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" priority="1" group="0" /> </soapExtensionTypes> </webServices> </system.web> <microsoft.web.services2> <!-- where the WSE2 configuration settings go --> ... </microsoft.web.services2> </configuration>

Figure 4 WSE 2.0 Assembly

Figure 4** WSE 2.0 Assembly **

With this in place, the project is now configured to use WSE 2.0. You can configure client applications to take advantage of WSE 2.0 the same way. When you enable WSE in a client application you ensure that all Web references will be WSE-enabled. This also takes care of setting up the <microsoft.web.services2> section in the project's app.config file.

If you're migrating an existing application from WSE 1.0 to WSE 2.0, you can follow this same procedure but then you must manually remove the WSE 1.0 assembly (Microsoft.Web.Services) from the references section as well as striking the <microsoft.web.services> section from the application configuration file.

After making these changes, try building the solution. If you're migrating a WSE 1.0 application, you'll probably get some errors that have to do with the incompatibilities described earlier. For example, you'll need to change namespace imports in order to use the WSE 2.0 namespace name and in addition you'll need to deal with object model differences.

Once you have WSE 2.0 installed and configured, you're ready to start taking advantage of its new features, most of which revolve around messaging, security, and policy. In fact, WSE 2.0 is the only supported Microsoft Web services solution currently shipping that implements the latest Web services specifications in those different areas. In addition to the baseline Web services specifications, WSE 2.0 also supports WS-Addressing, WS-Security, WS-Trust, WS-SecureConversation, WS-Policy, WS-PolicyAssertions, and WS-SecurityPolicy. The implementations of these specifications work together to provide a more robust and cohesive Web services solution. Let's take a look at some of these new features in more detail.

Messaging Enhancements

Using WSE 2.0 in conjunction with ASP.NET Web services provides a way to extend the basic functionality of a WebMethod with extra features such as security. WSE does this by taking advantage of the SoapExtension framework, which makes it possible to perform pre- and post-processing on the SOAP messages. The downside to this approach, however, is that ASP.NET Web services are tied to HTTP.

WSE also provides a lower-level messaging API that's completely transport neutral. WSE 2.0 supports sending and receiving messages over in-process, TCP, and HTTP channels. And you can even write custom channels if you need to send messages over transports that WSE doesn't currently support, such as Microsoft Message Queue Server (MSMQ).

WSE 2.0 provides two low-level classes for sending and receiving SOAP messages, called SoapSender and SoapReceiver. It also provides two higher-level classes that automate some of the most common SoapSender and SoapReceiver tasks such as object serialization, implementing request/response exchanges, and figuring out which operation to perform. These higher-level classes are called SoapClient and SoapService.

Let's take a look at an example that illustrates the differences between ASP.NET Web services and WSE 2.0. Consider the class definitions that model contact information (see Figure 6).

Figure 6 Class Definitions

[XmlType(Namespace="https://example.org/contacts")] public class Contact { public string name; public Address address; public string phone; public string email; } [XmlType(Namespace="https://example.org/contacts")] public class Address { public string street; public string city; public string state; public string zip; public string country; }

The sample shown in Figure 7 illustrates how to implement a simple Web service that adds and retrieves contacts from an internal store. As you can see, this sample was implemented using the traditional ASP.NET Web services framework using the [WebService] and [WebMethod] attributes.

Figure 7 ContactService Implemented in ASP.NET

[WebService(Namespace="https://example.org/contacts")] public class ContactManagerService : System.Web.Services.WebService { static Hashtable store = new Hashtable(); [WebMethod] [SoapDocumentMethod( ParameterStyle=SoapParameterStyle.Bare)] public void AddContact(Contact c) { store.Add(c.name, c); } [WebMethod] [SoapDocumentMethod( ParameterStyle=SoapParameterStyle.Bare)] public Contact GetContact(string name) { return (Contact)store[name]; } }

Figure 8 contains an equivalent implementation built using the WSE 2.0 messaging API. It contains a SoapService-derived class that can be bound to HTTP in order to provide the same functionality as the ASP.NET version. This class uses the WSE 2.0 [SoapService] and [SoapMethod] attributes. As you can see, the WSE 2.0 approach feels very similar.

Figure 8 ContactService Implemented in WSE 2.0

[SoapService("https://example.org/contacts")] public class ContactManagerService2 : SoapService { static Hashtable store = new Hashtable(); [SoapMethod("https://example.org/contacts/AddContact")] public void AddContact(Contact c) { store.Add(c.name, c); } [SoapMethod("https://example.org/contacts/GetContact")] public Contact GetContact(string name) { return (Contact)store[name]; } }

Both ContactService implementations (see Figure 7 and Figure 8) have the same wire-level interface. In other words, they expect and produce the same XML messages on the wire. Hence, both of these implementations should provide equivalent XML Schema and WSDL definitions to consumers.

The main difference between these implementations is that the ASP.NET Web services version is tied to HTTP while the WSE 2.0 version can be used with any transport. For example, you can bind the SoapService implementation to an HTTP endpoint through an <httpHandlers> mapping in web.config, as illustrated here:

<configuration> <system.web> <httpHandlers> <add type="ContactService.ContactManagerService2, ContactService" path="contactservice.ashx" verb="*" /> </httpHandlers> •••

Or, you can programmatically bind the SoapService implementation to a TCP endpoint, as illustrated in the following Windows®-based application:

private void Form1_Load(object sender, System.EventArgs e) { EndpointReference er = new EndpointReference( new Uri("soap.tcp://localhost/contactservice")); SoapReceivers.Add(er, typeof(ContactManagerService)); }

WSE 2.0 delivers on the promise of SOAP as a transport-neutral messaging protocol. Now you can add additional features to your services in a way that doesn't depend on how the messages are sent. For example, the security functionality you add via WSE 2.0 will work the same over HTTP or TCP channels.

There are some differences in the messaging object model since the Technology Preview release. One difference has to do with how you reference Web services endpoints in your code. The WS-Addressing specification defines a construct named EndpointReference for referencing endpoints in XML messages. WSE 2.0 supports this concept through the EndpointReference class. In order to maintain consistency with WS-Addressing, WSE 2.0 made changes throughout the entire object model to work with EndpointReference objects instead of raw Uri objects. This provides a more consistent and flexible model for referencing endpoints.

The WSE 2.0 interfaces for transports and channels have also been reworked substantially. This will require you to rework any custom channels you may have implemented on the Technology Preview release.

Check out the September 2003 installment of The XML Files for more details on the WSE 2.0 messaging API.

WSDL Support

Web Services Enhancements 2.0 now provides full support for WSDL, both in terms of generating and consuming definitions. WSE 2.0 automatically generates WSDL definitions for SoapService endpoints when requested.

If the SoapService endpoint is bound to an HTTP endpoint, you can request the WSDL definition by appending "?wsdl" to the endpoint address. This is the same approach used in the ASP.NET Web services framework. Assuming the SoapService implementation shown in Figure 8 is bound to https://localhost/contactservice/contactservice.ashx, you can retrieve its WSDL definition using https://localhost/contactservice/contactservice.ashx?wsdl.

The "?wsdl" approach doesn't make sense for protocols such as TCP that don't support the notion of a query string. Hence, WSE 2.0 also provides a generic approach for requesting WSDL definitions that can be used with any transport. Simply send a SOAP message with an action of https://schemas.microsoft.com/wse/2003/06/RequestDescription and an empty body, as illustrated here:

<soap:Envelope xmlns:wsa="..." xmlns:soap="..." ...> <soap:Header> <wsa:Action>https://schemas.microsoft.com/wse/2003/06/ RequestDescription</wsa:Action> ••• </soap:Header> <soap:Body /> </soap:Envelope>

And the WSE 2.0 endpoint will return the WSDL definition in the response SOAP message.

WSE 2.0 also ships with a new command-line tool named WseWsdl2.exe that will automatically generate SoapClient proxy classes from WSDL definitions. The default installation puts this tool in C:\Program Files\Microsoft WSE\v2.0\Tools\Wsdl. WseWsdl2.exe currently supports HTTP and TCP endpoints. The following command illustrates how to generate a proxy for a TCP endpoint, which must be running for this to work:

C:> wsewsdl2.exe soap.tcp://localhost/contactservice proxy.cs

In this case, the tool will automatically send a RequestDescription message to the endpoint, retrieve the WSDL from the response, and use it to generate the proxy class.

Security Enhancements

WSE 2.0 now supports the OASIS WS-Security standard, which primarily affects the message format but not the overall functionality introduced by the prior version of WS-Security. Most of the remaining security enhancements are a result of work by Microsoft to simplify and automate the most common Web services security tasks.

Let's take authentication for example. WSE 1.0 required you to write an IPasswordProvider class to manually authenticate incoming UsernameToken elements. WSE 2.0, on the other hand, automatically authenticates incoming UsernameToken elements against Windows when the password is supplied in clear text. The IPasswordProvider approach has been completely reworked around a new interface named ISecurityTokenManager. You use ISecurityTokenManager to implement custom authentication schemes as well as binary and custom XML security tokens. WSE 2.0 ships with several samples that illustrate how you can accomplish this.

WSE 2.0 has improved overall security token support. WSE 2.0 makes it possible to sign and encrypt messages using any security token, including UsernameToken, and it provides a way to automatically generate DerivedKeyTokens that are more secure. WSE 2.0 also adds support for Kerberos security tokens. The new Kerberos support, however, requires Windows Server™ 2003 or Windows XP Service Pack 1.

WSE 2.0 tries to simplify working with X.509 certificates, one of the more commonly used binary security tokens for signing and encrypting messages. WSE 2.0 ships with a new tool named WseCertificate2.exe that makes it easy to retrieve certificate details that you need to use in application configuration settings. The tool lets you retrieve the certificate's key identifier and set the private key properties (see Figure 9). It will come in handy when you start doing a lot of work with certificates.

Figure 9 WSE Certificate Tool

Figure 9** WSE Certificate Tool **

WSE 2.0 also provides a complete role-based authorization model for securing access to a service. This is provided through the IPrincipal interface on security tokens. You can use the IsInRole method for authorization-specific user roles. This can also be done declaratively through policy statements.

WSE Security Settings Tool

Another major simplification provided by WSE 2.0 is the new WSE Security Setting Tool. This wizard facilitates the creation of policy files that describe the security requirements of the application. The policy, in turn, automates the security code you had to write to lock down your service in WSE 1.0 by requiring security tokens, signatures, or encryption. The policy can also automate the process of signing and encrypting messages with security tokens before they're sent by a client.

You can run the tool by opening the WSE Settings tool, navigating to the Policy tab, and selecting Enable Policy. Then press Add, enter the endpoint you want to describe (or leave <DefaultEndpoint>), and press OK to launch the Security Settings Wizard.

When you run the wizard, it asks you if you want to secure a client or a service application so it knows which options to provide. Then it asks you to specify signatures/encryption requirements for the request and response messages. Next, it asks you to specify the type of token to use for client authentication—you can choose Username, Kerberos, or X.509 Certificate. Finally, depending on your choices, it may ask you to select a certificate from the certificate stores on the machine, and then you're finished.

When you finish the wizard, it generates a new policy file with all of the specified settings and adds it to your project. It also registers the policy file in your application configuration file, as illustrated here:

<configuration> ••• <microsoft.web.services2> ••• <policy> <cache name="policyCache.config" /> </policy> </microsoft.web.services2> </configuration>

This represents another change from the Technology Preview release: you no longer have to register "send" and "receive" policies separately in the configuration file. Now, both send and receive requirements are described in a single policy file. As a result, the policy mapping schema has changed substantially in WSE 2.0. However, being able to create policies through the wizard shields you from the differences.

WSE 2.0 also lets you write custom policy assertion handlers if you want to extend the built-in policy functionality offered in this release. Check out WS-Policy and WSE 2.0 Assertion Handlers for more details.

Once you've finished running the WSE Security Settings Tool wizard, your application will automatically support the security features you selected. It will enforce the specified requirements (such as the restriction that the message must contain a UsernameToken and a signature) when messages are received. It will also enforce policies when messages are sent, modifying the message if necessary to conform to the requirements. You can provide security tokens for WSE to use ahead of time through PolicyEnforcementSecurityTokenCache.GlobalCache. This greatly simplifies the process of integrating new security features into your applications since you no longer have to deal with writing the code necessary to make it happen.

Automatic Secure Conversation

WSE 2.0 completely automates the use of secure conversation between clients and services. By secure conversation, I mean support for WS-Trust and WS-SecureConversation. These specifications define how to derive a session token that can be used over multiple operations, improving efficiency.

You can enable secure conversation in a service application by running the WSE Security Settings Tool and selecting "Use Secure Conversation" on the first step. This will insert additional entries into the generated policy and it will inject the <tokenIssuer> element into the application configuration file, as illustrated here:

<configuration> ••• <microsoft.web.services2> ••• <tokenIssuer> <autoIssueSecurityContextToken enabled="true" /> </tokenIssuer> </microsoft.web.services2> </configuration>

You have to do the same thing in each client application that wants to take advantage of secure conversation. Once you've finished running the wizard in both applications, they'll begin using secure conversation to communicate with each other.

Next-Hop Routing

WSE 2.0 has moved away from the WS-Routing routing model introduced by WSE 1.0 due to various security issues. WSE 2.0 now supports a next-hop routing model, where routing decisions are made on a node-to-node basis without requiring an explicit routing path in the message header. As a result, all WS-Routing functionality has been removed and the new routing model is based entirely on WS-Addressing headers.

WSE 2.0 still relies on WS-Referral for next-hop routing instructions. The built-in router class is called Microsoft.Web.Services2.Messaging.SoapHttpRouter and can be registered in web.config the same way as before.

This change in routing behavior essentially makes it possible to route messages in a more secure way, without needing to modify the message en route. Check out the MSDN online article "Moving from WS-Routing to WS-Addressing Using WSE 2.0" for more details on routing and addressing.

Where are We?

WSE 2.0 is the only existing Microsoft solution that makes it possible to take advantage of the latest emerging Web services specifications. WSE 2.0 is full of new features and tools that simplify the overall development and configuration process. WSE 2.0 automates many of the tasks that WSE 1.0 required you to implement manually, making it easier to get things up and running quickly without sacrificing correctness or flexibility. If you'd like to dig in further, check out the samples that ship with WSE 2.0, available in both C# and Visual Basic® .NET.

Send your questions and comments for Aaron to  xmlfiles@microsoft.com.

Aaron Skonnard is a co-founder of Pluralsight, an education and content creation company, where he focuses on XML and Web services technologies. He's a contributing editor to MSDN Magazine and the author of several books, including Essential XML Quick Reference (Addison-Wesley, 2001).