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
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.
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
<service> element to initialize the
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
directive. For example, this Service.svc endpoint
references the service type
<% @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
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:
address="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
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" > <endpoint
address="Soap11"contract="HelloIndigo.IHelloIndigoService" binding="basicHttpBinding"/> <endpoint
address="Soap12"contract="HelloIndigo.IHelloIndigoService" binding="wsHttpBinding"/> </service>
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:
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.
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.
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.
The service model provides its own
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,
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
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.
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.Currentis 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
If you are porting existing ASP.NET web services (ASMX) you may
have existing code that relies on the
other ASP.NET features. For example, you may want to access the ASP.NET
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
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> <system.serviceModel>
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
Profile. Consider this
<profile> section in the web.config:
<profile enabled="true" automaticSaveEnabled="true"> <properties> <add name="Culture" allowAnonymous="true" defaultValue=""/> </properties> </profile>
profile creates a single property,
service code could access the profile for the current user as follows, using the current
// set the culture preference string culture = HttpContext.Current.Profile["Culture"]; // get the culture preference HttpContext.Current.Profile["Culture"] = culture;
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.
The following code sample illustrates ASP.NET compatibility: <YourLearningWCFPath>\Samples\Hosting\ASPNETCompatibility.