Hosting WCF Services (cont'd)
Associating with a ServiceHost
Regardless of the hosting environment, all WCF services must be associated with a ServiceHost instance to be accessible at run time. ServiceHost is part of the System.ServiceModel namespace, and is the centerpiece of the hosting story. A ServiceHost instance is initialized with information about the service type, one or more service endpoints, optional base addresses, and behaviors that govern how the service model processes requests to the service.
advertisement


Initializing the ServiceHost
Listing 1 illustrates a simple example of a console host application initializing the ServiceHost programmatically. In fact, this listing is the entire listing for the host application. The application constructs a ServiceHost instance on startup, supplying the service type: HelloIndigo.HelloIndigoService. A single endpoint is created exposing its HelloIndigo.IHelloIndigoService contract over NetTcpBinding. In this example, the endpoint is initialized with a complete URI, removing the need for any base addresses.

After calling the Open() method the ServiceHost begins listening for messages. While the Console.ReadLine() statement blocks the console application to keep the process alive, the application processes incoming requests on their own thread taken from the thread pool. After closing the console, the using statement disposes of the ServiceHost instance calling its Close() method. At this point new requests are rejected while currently processing requests complete gracefully.

In this example, the console host only exposes one service. To expose multiple services, you can open multiple ServiceHost instances within the same host process.

Declarative Configuration
You can also initialize the ServiceHost declaratively via application configuration. In the <system.serviceModel> section you can specify one or more services in the <services> section. Here is an example of declarative service configuration:

   <service name="HelloIndigo.HelloIndigoService">
     <endpoint 
       address= "net.tcp://localhost:9000/HelloIndigoService" 
       binding="netTcpBinding" 
       contract="HelloIndigo.IHelloIndigoService" />
   </service>
As with programmatic initialization, you must specify the service type and one or more endpoints. This example illustrates how to configure a single endpoint similar to the code in Listing 1, with the addition of a metadata exchange endpoint.

"Processing requests on the UI thread is not practical for services that require decent throughput on the server. In fact, it is unlikely that a service that processes significant requests will even have a UI associated with it."
When you construct the ServiceHost instance it looks for a <service> section matching its service type, and initializes itself from those settings. Initializing the ServiceHost declaratively removes hard-coded base addresses and endpoints from the code, as shown here:

   using (ServiceHost host = new ServiceHost( 
      typeof(HelloIndigo.HelloIndigoService)))
   {
      host.Open();
      // other code
   }
Base Addresses
If you specify a fully qualified URI for each service endpoint, you do not need a base address to initialize the ServiceHost. At run time, if you provide base addresses to the ServiceHost constructor you can optionally provide a relative URI to the endpoint address as shown here:

   using (ServiceHost host = new ServiceHost( 
      typeof(HelloIndigo.HelloIndigoService), 
      new Uri("net.tcp://localhost:9000")))
   {
      host.AddServiceEndpoint(typeof(
         HelloIndigo.IHelloIndigoService), 
         new NetTcpBinding(), "HelloIndigo");
      host.Open();
      // other code
   }
Declaratively, the application provides base addresses in the <host> section for the service configuration:

   <service name="HelloIndigo.HelloIndigoService">
     <host>
       <baseAddresses>
         <add baseAddress="http://localhost:8000"/>
         <add baseAddress="net.tcp://localhost:9000" />
       </baseAddresses>
     </host>
     <endpoint binding="netTcpBinding" 
       contract="HelloIndigo.IHelloIndigoService" />
     <endpoint  address="mex" binding="mexHttpBinding" 
       contract="IMetadataExchange"/>
   </service>
The ServiceHost builds endpoint addresses by appending the relative address of each endpoint to the base address matching the endpoint's binding protocol. For example, the NetTcpBinding endpoint shown in the preceding code uses the net.tcp base address while the MexHttpBinding metadata exchange ("mex") endpoint uses the http base address. If you omit the address from the <endpoint> configuration, the ServiceHost assumes the base address to be the endpoint address.

Service Description
 
Figure 1: The ServiceDescription generates the WSDL document and services WS-MetadataExchange requests.
The ServiceHost instance is responsible for generating a service description for its service. This service description incorporates information about the service type, all service endpoints, and any behaviors that are attached to the service-exposing it through its Description property, a ServiceDescription instance.

ServiceDescription is part of the System.ServiceModel.Description namespace. It is a run-time abstraction that ultimately generates the Web service Description Language (WSDL) document for the service, and supports interactive metadata exchange (WS-MetadataExchange) with clients. By default, the ServiceHost uses reflection to generate the description-inspecting the service, its contracts, and relevant service behaviors. Figure 1 illustrates how clients can use SvcUtil (svcutil.exe) or the WS-MetadataExchange protocol to initialize a channel at the client and consume a service.

Under most circumstances you will not interact directly with the ServiceDescription. However, for advanced scenarios you can control how the ServiceHost generates this ServiceDescription by subclassing ServiceHost and overriding the CreateDescription() method.

ServiceHost Events
The ServiceHost notifies you of state changes in the channel stack through CommunicationObject events. ServiceHost inherits ServiceHostBase, which inherits CommunicationObject. CommunicationObject is a common base type for many objects participating in the communication channel-providing a common state machine. The events it exposes include Opening, Opened, Closing, Closed, and Faulted.

Closing and Faulted are particularly useful for writing event logs or notifying administrators when the communication channel for your service is closing or has encountered a problem. Just add these event handlers to the ServiceHost instance before you open the communication channel, as shown here:

   using (ServiceHost host = new ServiceHost( 
      typeof(HelloIndigo.HelloIndigoService)))
   {
      host.Closed += new EventHandler(host_Closed);
      host.Closing +=new EventHandler(host_Closing);
      host.Faulted +=new EventHandler(host_Faulted);
      host.Open();
      // other code
   }
The ServiceHost also has a State property based on the CommunicationState enumeration. You can use this property to detect the following states: Created, Opening, Opened, Closing, Closed, or Faulted.

Previous Page: Introduction Next Page: Self-Hosting
Page 1: IntroductionPage 4: Managed Windows Services
Page 2: Associating with a ServiceHostPage 5: Message-Based Activation
Page 3: Self-HostingPage 6: IIS 7.0 and WAS Hosting