Let me start with something simple for this topic. I first make a few assumptions here:
- You have used Microsoft Internet Information Services (IIS).
- You are familiar with .NET Programming with Common Language Runtime (CLR) and ASP.NET.
- You have heard of Microsoft Windows Communications Foundation (WCF), code-named “Indigo”.
That is all what you need to know before reading the following!
Below I will write about how to host a WCF service in a special “hosting” environment.
There are tons of articles and blogs out there talking about Service Oriented Architecture (SOA), Web Services, and WCF. Never mind if you have not read them. So I will make things as simple as possible. Basically, WCF, as the next generation of service-oriented programming platform, provides a set of .NET APIs in its Version 1 (V1) for developers to use. It will be released as part of a larger package WinFX. You can download the most recent PDC release from here.
Every service-oriented programming model is also a client-server model. WCF has no difference. Both the client and service counterparts of WCF are based on the so-called “ABC” model: Address, Binding, and Contract. People also call this as “WHW” model: Address stands for “Where”, Binding stands for “How”, and Contract stands for “What”. Among the three, Binding is the most complicated part in this model. It tells WCF how to transfer data between the client and the service:
- What transport do we use: HTTP, TCP, MSMQ, Named Pipe, etc?
- What encodings do we use for the data to be encoded?
- What security mechanisms do we use for the underlying channels?
For each WCF service, there is a host that manages service instances and lifetime. The base type of the host is System.ServiceModel.ServiceHost. It provides events and extensibility points for you to programming with. Actually I am lying here. ServiceHost is not the most basic service host type, but System.ServiceModel.ServiceHostBase is. However, you will never touch this base type if you do not want to re-create the whole channel stack to replace WCF underlying implementations.
How far have I diverted from my topic? Aren’t we talking about WCF service hosting? No, not yet! The concept of “host” has relative meanings in different programming plug-in layers. The “host” that I will talk about here has a broader meaning: it is application-level “host”. That is, a host is an application that loads one or more WCF ServiceHosts, which we will call services in the following, and manages their lifetime. In some cases, it provides an environment that works as the entry point for all messages that are routed to the services. Am I clear here? If not, please read on.
There are different types of hosting environments for WCF services. To understand how these hosting environments work, we need to go back to see how the predecessor of WCF, a.k.a., ASMX works.
When ASP.NET V1 was shipped, a Web service framework known as ASMX was introduced. It is tightly integrated with the ASP.NET HTTP pipeline. This pipeline provides the hosting environment to ASMX services and it is almost always hosted inside ASP.NET applications which are managed by IIS. In this way, ASMX services can leverage the advantages of ASP.NET applications such as process management, application recycling, configuration and deployment, and extensibility points provided by ASP.NET HTTP pipeline.
It is not required to have IIS to run ASMX services. For example, you can use the ASP.NET Cassini sample web server to host an ASP.NET application and thus ASMX services. You also build a web server into your own application to host the ASP.NET pipeline using the managed HTTP.sys utility System.Net.HttpListener(see Run ASMX without IIS).
However, ASMX services cannot run without the ASP.NET HTTP pipeline. Even though you can integrate the pipeline into your application as above, you still need to think of the ASMX services as being in a different world, that is, they have their own configuration and deployment which are quite web-flavored. In this sense, WCF services go one big step beyond to make service-oriented programming real.
The fact that ASMX services are tightly coupled with ASP.NET HTTP pipeline is due to the flat and passive HTTP request handling mechanism. HTTP requests received from IIS are passed on to ASP.NET pipeline and then are consumed by service methods.
WCF services, however, are based on a strictly layered model to break this paradigm. Roughly speaking, there are three different layers for WCF services:
- ServiceModel layer
- Channel layer
- Transport layer
This layered model is similar as the Open System Interconnection (OSI) model. The lowest Transport layer is responsible for listening and receiving requests and converting the received data into “Messages”. A Message is a cross layer data packet that travels all of the layers to the top. The Channel layer provides a Message processing framework for different service requirements. In the real implementation, it actually consists of one or more sub-channel layers such as Basic layer, Security layer, ReliableMessaging layer, Transaction layer, etc. The top ServiceModel layer is the application layer that manages service instances and invokes service operations. It provides Object Models (OM) for people to program with.
In this layered model of WCF services, the top SericeModel layer is also responsible for building the lower level layers in different hosting environments. It also makes the Transport layer to be freely chosen among different communication protocols. This is why it does not rely on the ASP.NET HTTP pipeline as ASMX services does.
As mentioned above, WCF services are hosted by a ServiceHost. Ideally, any application or environment can create ServiceHost to host WCF services. In reality, we classify the different environments into three categories:
- Windows Activation Service (WAS) hosting environment
- EXE applications
- NT Services
The WAS hosting environment is a broad concept that extends the ASP.NET HTTP pipeline hosting concept for ASMX services. WAS is an NT service in Windows Vista. It is separated out from the legacy IIS as a standalone Windows component that provides protocol-agnostic activation mechanism for different protocols besides HTTP. The IIS, Cassini, and any custom Web Server flavored hosting environments also fall into this category since they share the same WCF service deployment and activation mechanism. I will talk about this more in later sections.
You can easily host a WCF service in an EXE application so that you can control the lifetime of the ServiceHost. Furthermore, the WCF service shares the same configuration file with the application. This hosting environment is mostly useful when you also build your client code into the application. A good example is that a sophisticated business application with 3-tier architecture can have WCF services to pass messages between different layers.
NT Services are special EXE applications which are long running and the lifetime is controlled by Service Control Manager (SCM). Because of the long running behavior, you need to be careful of all of different requirements for writing an NT Service: security, reliability, and performance. You can use Microsoft Visual Studio to create managed NT Services with “Windows Service” project type.
As mentioned above, a WCF service works similarly as an ASMX Service. For HTTP protocol, it relies on ASP.NET HTTP pipeline to transfer data. For non-HTTP protocols such as Net.Tcp, Net.Pipe, and Net.Msmq etc, it relies on the extensibility points, i.e., ProcessProtocolHandler (PPH) and AppDomainProtocolHandler (ADPH), of ASP.NET to transfer data. We will use the term “protocol handler” interchangeably to refer to either the ASP.NET HTTP pipeline or the ADPH. In the context of this writing, WCF services hosted in this environment are called WAS hosted services or simply called hosted services, and in contrast, services hosted in NT Services or EXE applications are called self-hosted services.
Let’s first take a look at a simple hosted service and see how it works.
A hosted service requires a physical service file with extension “.svc” to be associated with it. Here is the content of a simple service file HelloWorld.svc:
<%@Service Language="C#" Class="HelloWorld.HelloService" %>
public interface IHelloContract
string Hello(string greeting);
class HelloService : IHelloContract
public string Hello(string greeting)
return "You said: " + greeting;
This file has a Service directive which is enclosed in the “<% %>” block and it also contains inline C# code. The Service directive tells the hosting environment which Service this file points to.
Just as ASMX services, the code can be compiled into a DLL that is deployed to the Global Assembly Cache (GAC), or to the application’s “\bin” directory, or it can be put in a C# file under the application’s “\App_Code” directory.
With this service file, we have defined a service contract IHelloContract and the service implementation. However, the service still does not have an endpoint defined yet. You can either define an endpoint declaratively through the configuration file “web.config” or imperatively through code. The latter will be covered separately in a different blog later.
The service configuration inside the web.config file is very similar as that of self-hosted services. Here is an example of web.config file for the above service:
<?xml version="1.0" encoding="utf-8"?>
I need to point out a few points for this config file:
1) Service Type Attribute: The service type “HelloWorld.HelloService” specified here plays as a lookup key for the corresponding HelloWorld.svc. It tells the hosting environment which service will take the configuration specified here.
2) Endpoint Address: I did not specify the “address” of the endpoint here. The endpoint address is the same as the base address in this case. I will expand this in the next section.
3) Nested web.config: The service configuration can be specified in nested web.config files. For ASP.NET applications, a web.config file can locate in any sub-directories or virtual web directories as well as the root of the virtual application. All of the settings in the nested web.config files are merged for the virtual ancestors of the directory where the .svc file locates.
The .svc file does not contain much useful information except for providing the service type which is also specified in the web.config file. Then why do we need .svc files after all? The main reason is that we need them to provide intuitive addressing model.
Suppose that we drop the above HelloWorld.svc file into a virtual application “/test”, we automatically have the following base address for the service:
You can enable different protocols for a single ASP.NET application. Each protocol needs to have a protocol binding for the whole web site. For IIS6 and below, the only protocol that is supported is HTTP (which implies HTTPS).
The WAS hosting environment looks up all enabled protocols for the ASP.NET application and generates the base addresses for the hosted service. Each base address has the following format:
You can access the base addresses through the ServiceHostBase.BaseAddresses property. In WCF V1, only one base address is supported for each protocol. So if there are two or more bindings for HTTP is specified, you will get an ArgumentException on the service side with error message “Collection already contains an address with scheme http”.
Note: It is NOT recommended to specify an absolute address (with protocol scheme included) to the endpoint in web.config, otherwise, you will get AddressAccessDeniedException on the service side if the address does not match the service base address up to the application path (<apppath>) or EndpiontNotFoundException if you happen to match the application path but not the service path.
The WAS hosting environment is represented by the public type System.ServiceModel.ServiceHostingEnvironment. It is responsible for service activation, that is,
· It finds the service compilation information from System.Web.Compilation.BuildManager
· It creates the ServiceHost instance to host the service with compilation information.
· It then calls ServiceHost.Open to build the layers.
· It then caches the service and manages its lifetime inside the AppDomain.
This whole process is exposed through the following public method:
public static void EnsureServiceAvailable(string virtualPath)
This API is protocol agnostic. It is an extensible point for a custom protocol handler to activate the service.
The service activation process has the following characteristics:
1) Activation on demand: A WCF service is activated in the AppDomain only if EnsureServiceAvailable is called by one protocol handler for that service. Once it is activated, it will be active in the AppDomain until the AppDomain is unloaded.
2) Activation once for all: A WCF service can be activated from any protocol handler. Once it is activated, it is activated for all endpoints and thus all protocols. So when a second protocol handler calls EnsureServiceAvailable, it is a no-op as the service has been activated.
Hosted WCF services enjoy all of the features for ASP.NET applications. One of the major feature is application recycling including AppDomain recycling and process (or AppPool) recycling. There are different factors that can cause application recycling to happen. See “Recycling Application Pool Settings” for more information about process recycling. When the worker process is recycled, all of the AppDomains in that process are also recycled. The configuration setting HostingEnvironmentSection.IdleTimeout can control AppDomain recycling. Also an AppDomain can be recycled if critical files for the application are changed. These files include web.config, assemblies in the “\bin” directory, code files in the “\App_Code” directory, etc.
Whenever a .svc file is modified in application, the AppDomain is also recycled. This is to simplify the service recycling mechanism. When the AppDomain is recycled, the ServiceHostingEnvironment tries to close all of the cached WCF services in a timely manner. Services not closed timely are aborted at the end. The timeout is controlled by the HostingEnvironmentSection.ShutdownTimeout property.
The drawback of service recycling is that all of the sessionful data is lost. This means that Security and ReliableMessaging break when recycling happens. The workaround is to leverage the ASP.NET state service features by enabling AspNetCompatibility mode. I will expand on this in a later blog.