Hosting in IIS 6.0

When you expose WCF services over the Internet using HTTP protocol on a Windows Server 2003 machine, IIS 6.0 provides a much richer hosting environment than self-hosting. Unlike self-hosting, no code is required to instantiate ServiceHost instances, but you can still use declarative configuration in the application’s web.config file. More importantly, IIS 6.0 provides other much-needed hosting features for idle-time management, health monitoring, process recycling, and management tools for configuring application pools.

In the first three chapters of this book, you have created ASP.NET web sites to host WCF services, completed labs that used the various WCF service templates to help get you started, and experienced some of the differences between self-hosting and IIS hosting. In this section, I’ll review how IIS hosting works in general terms, discuss its distinct behaviors and added value, and provide you with an architectural overview of the IIS 6.0 hosting environment. In addition, I’ll discuss ASP.NET compatibility mode, which allows you to host WCF services through the ASP.NET pipeline to assist with migration of ASP.NET web services.

IIS Service Endpoints

When you host your services with any version of IIS, you must provide at a minimum the following:

  • An addressable web site or virtual directory for your service endpoints

  • A file with the extension .svc that will help activate the ServiceHost instance

  • A service type that is linked to the .svc file for activation

As illustrated in labs from earlier chapters, you can use the WCF Service project template when you create a new web site project using Visual Studio. This template generates a project with a .svc endpoint, a sample service implementation, and a web.config with the appropriate <service> element to initialize the ServiceHost.

The .svc endpoint is the file that clients will address in their target URI to reach the service. It contains a @ServiceHost directive that indicates the service type, and if applicable, the source code in the App_Code directory where the service code can be found:

<% @ServiceHost Language=C# Debug="true" Service="MyService" CodeBehind="˜/App_Code/
Service.cs" %>

In reality, your services will be compiled into separate assemblies, so your web site project must reference those assemblies, and the .svc endpoint will reference the type only through the Service property of the @ServiceHost directive. For example, this Service.svc endpoint references the service type HelloIndigo.HelloIndigoService:

<% @ServiceHost Service="HelloIndigo.HelloIndigoService" %>

As I explained in earlier chapters, the service type specified in the @ServiceHost directive also tells the service model which <service> section to use from the web.config to initialize the ServiceHost instance.

One of the distinctions between self-hosting and IIS hosting is that the base address is provided by the web site or virtual directory for the application. The <service> section needn’t provide an address for each endpoint, since the .svc file is the endpoint:

<service name="HelloIndigo.HelloIndigoService" >
  <endpoint contract="HelloIndigo.IHelloIndigoService" binding="wsHttpBinding"/>
</service>

Clients address the service using the .svc endpoint, for example:

<client>
  <endpointaddress="http://localhost/IISHost/Service.svc" binding="wsHttpBinding"
contract="Client.localhost.HelloIndigoContract" />
</client>

In cases where you might want to expose multiple endpoints for the same .svc endpoint, you can use relative addressing. This example illustrates a case where a single IIS endpoint, Service.svc, can be accessed using BasicHttpBinding or WSHttpBinding to support different web service protocols. The <endpoint> configuration for the service uses relative addressing, appending “/Soap11” and “/Soap12” to the endpoint address:

<service name="HelloIndigo.HelloIndigoService" >
  <endpointaddress="Soap11" contract="HelloIndigo.IHelloIndigoService"
binding="basicHttpBinding"/>
  <endpoint address="Soap12" contract="HelloIndigo.IHelloIndigoService"
binding="wsHttpBinding"/>
</service>

Tip

The web service lab from Chapter 3 shows you how to implement multiple WCF endpoints for a single IIS service endpoint.

Clients address these service endpoints in this way:

http://localhost/IISHost/Service.svc/Soap11
http://localhost/IISHost/Service.svc/Soap12

For file-based web sites, the ASP.NET Development Web Server is used instead of IIS, which can be useful for testing only. Endpoints function in the same way as with HTTP-based web sites hosted in IIS, with the exception that a dynamically generated port assignment will exist in the endpoint address; for example, http://localhost:1260/FileBasedHost/Service.svc. This port is saved in the project settings so that the same port is used on subsequent tests.

Tip

At times this port assignment can change, and if so will invalidate hardcoded client endpoints. If you see unexpected behavior, don’t forget to check that the client and service are using the same port.

IIS 6.0 Hosting Architecture

One of the most important features IIS provides your WCF services is message-based activation, something I touched on in Chapter 1. ServiceHost instances need not be open prior to processing requests for a given endpoint. Instead, the World Wide Web Publishing Service (“WWW Service”) is responsible for ensuring that a worker process is present to handle requests. Then, when requests for a particular .svc endpoint are forwarded to the worker process, the service model initializes the corresponding ServiceHost (if necessary) before the request is dispatched.

This message-based activation process allows IIS to balance the number of worker processes required to service the request load, releasing unused resources where appropriate. IIS also monitors the health of each worker process and will launch a new, healthy worker process for requests as needed. In addition, IIS can be configured to periodically recycle worker processes to reduce the risk of resource and memory leaks. These features improve the overall reliability and availability of your WCF services.

There are a few key participants in this activation process:

  • The HTTP Protocol Stack (http.sys) was introduced with IIS 6.0. It is a kernel-mode message processing service that can receive messages even while worker processes are not yet running. All requests arrive and return through this service.

  • The WWW Service is responsible for launching worker processes on demand to handle requests. It also determines the correct request queue (application pool) for messages to be sent from http.sys for processing. WWW is a Windows service that must be running for http.sys to successfully forward requests.

  • Requests for .svc endpoints are forwarded to an ASP.NET worker process because IIS is configured to forward requests to .svc extensions to the ASP.NET ISAPI Extension (aspnet_isapi.dll). The ASP.NET processing pipeline then relies on HTTP modules and handlers to process the request. An HTTP module is a component that can interact with any part of the request lifecycle by handling application events that are fired at specific points during request processing. An HTTP handler is the component responible for processing the incoming request stream and writing an appropriate response to the response stream. The service model provides implementations of these components to intercept and handle service requests, ensuring (as appropriate) that they are processed by the service model rather than the traditional ASP.NET pipeline.

Figure 4-15 illustrates how IIS 6.0 processes requests to WCF services. In fact, up to the point that the request reaches the worker process, it behaves much like any other request that is handled by aspnet_isapi.dll. The difference is in what happens after the ASP.NET pipeline gets hold of the request. For all requests, configured HTTP modules have an opportunity to interact with request processing at specific points in the lifecycle of the request by handling specific application events.

At some point during request processing, the pipeline also looks for an HTTP handler type that should be constructed to process the request according to file extension. Ultimately, the HTTP handler is responsible for processing requests, but this usually happens after the pipeline has had a chance to authenticate the call, verify that the request was not previously cached, reestablish the session if applicable, and process any other code injected by HTTP modules early in the request lifecycle. After the handler executes, HTTP modules then have another opportunity to interact with the response as it flows back through IIS to the client. Since service operations should be handled by the WCF processing model, not ASP.NET, the service model alters this pocessing lifecycle.

IIS 6.0 architecture for processing requests to WCF services

Figure 4-15. IIS 6.0 architecture for processing requests to WCF services

The service model provides its own HttpModule and HttpHandler types, located in the System.ServiceModel.Activation namespace. Both of these components interact with requests directed to a .svc endpoint using traditional ASP.NET configuration settings. As far as ASP.NET is concerned, the HttpHandler type is the target for request processing, but that would mean the request would pass through the usual ASP.NET pipeline with all of the configured modules for forms authentication, caching, and session, for example. By default, the service model bypasses this by pipeline, by hijacking requests targeting .svc endpoints and forwarding them to the service model for processing.

The service model HttpModule gets engaged very early in the lifecycle, handling the PostAuthenticateRequest event and, by default, forwarding the request to the service model. In fact, the service model allocates a thread from the WCF thread pool (to be discussed in Chapter 5) and releases the ASP.NET thread so that another incoming request can use it. This behavior ensures that all requests to WCF services are processed in a consistent manner, regardless of whether they are self-hosted or hosted in IIS. The service model handler is never invoked unless ASP.NET compatibility mode is enabled—something I’ll talk about shortly.

ASP.NET Compatibility Mode

Once the ServiceHost is activated, hosting a WCF service with IIS operates much the same as self-hosted services. That is, the service model has a consistent way of processing requests. By default, the ASP.NET processing model is only involved until the service model’s HTTP module forwards requests to a WCF thread, allowing the initial ASP.NET thread to be returned to the ASP.NET thread pool.

In fact, the service model has two modes for hosting WCF services:

Mixed Transports Mode

This is the default hosting mode. In this mode, service requests are not processed by the ASP.NET pipeline. This makes it possible for endpoints to be exposed for multiple transports in a consistent manner.

ASP.NET Compatibility Mode

This hosting mode restricts an application to exposing only HTTP services. When this is enabled, the features supplied by HTTP modules, such as file and URL authorization, session state, caching, and profile, are available to the service. In addition, HttpContext.Current is initialized to provide access to ASP.NET specific context.

In most cases, access to ASP.NET features and the HttpContext should not be necessary. The service model provides a much richer set of authentication and authorization features that are more appropriate for SOA. A global OperationContext is also supplied with access to contextual information for the request, including the security context, the request message and related headers, and information about the hosting environment.

If you are porting existing ASP.NET web services (ASMX) you may have existing code that relies on the HttpContext or other ASP.NET features. For example, you may want to access the ASP.NET Session, Cache, or Profile objects to provide a consistent runtime experience as you would have with ASMX. In this case, ASP.NET compatibility mode may be appropriate. You can enable ASP.NET compatibility by setting the aspNetCompatibilityEnabled property to true in the <serviceHostingEnvironment> section:

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<system.serviceModel>

This makes it possible for your service code, or its downstream objects, to interact with these aforementioned ASP.NET features. For example, you can write code that relies on the ASP.NET Profile. Consider this <profile> section in the web.config:

<profile enabled="true" automaticSaveEnabled="true">
  <properties>
    <add name="Culture" allowAnonymous="true" defaultValue=""/>

  </properties>
</profile>

This profile creates a single property, Culture. Your service code could access the profile for the current user as follows, using the current HttpContext:

// set the culture preference
string culture = HttpContext.Current.Profile["Culture"];

// get the culture preference
HttpContext.Current.Profile["Culture"] = culture;

If a service plans to use these features, because it was migrated from an ASMX web service perhaps, it should require that they are deployed to a hosting environment that supports ASP.NET compatibility by applying the AspNetCompatibilityRequirementsAttribute from the System.ServiceModel.Activation namespace, as follows:

[AspNetCompatibilityRequirements(
RequirementsMode=AspNetCompatibilityRequirementsMode.Required)]
public class ProfileService : IProfileService

Other than porting ASMX services, you will most likely avoid using this feature in order to provide a consistent hosting model for your services over multiple protocols.

Tip

The following code sample illustrates ASP.NET compatibility: <YourLearningWCFPath>\Samples\Hosting\ASPNETCompatibility.

Get Learning WCF now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.