To expose WCF service, you need to provide a host environment to run the service. Like the need to create .NET CLR host environment for managed code in general, WCF hosting environment to run in the same application domain process. ServiceHost can create one or more instances of the application domain, a relationship as shown below:


Figure hosting a ServiceHost

WCF ServiceHost is not recommended to create multiple instances of the application domain. If a plurality of services to be managed, it can expose multiple services through multiple WCF Endpoint in a host. Since the application domain of security have been isolated, if necessary to provide a different security context, it is necessary to create more than one instance of ServiceHost.

A typical host WCF include the following four:
1, "Self-Hosting" in the Application Managed A (self-managed hosting)
2, Windows Managed Services (Windows Services Host)
3, Internet Information Services (IIS host)
4, Windows Process Activation Service (WAS host)

below describes these and related host escrow precautions respectively through a specific example. In such an instance, we define a service contract following:

namespace BruceZhang.WCF.DocumentsExplorerServiceContract
{
    [ServiceContract]
    public interface IDocumentsExplorerService
    {
        [OperationContract]
        [FaultContract(typeof(DirectoryNotFoundException))]
        DocumentList FetchDocuments( string homeDir);
       
        [OperationContract]
        Stream TransferDocument(Document document);       
    }   
}

Service implementation is shown as follows:

namespace BruceZhang.WCF.DocumentsExplorerServiceImplementation
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class DocumentsExplorerService : IDocumentsExplorerService
    {
        #region IDocumentsExplorerService Members

        public DocumentList FetchDocuments( string homeDir)
        {
            //implementation code
        }       

        public Stream TransferDocument(Document document)
        {
            //implementation code
        }

        #endregion    
    }
}

In the operation of the service contract, DocumentList the Document as a custom data contract:

namespace BruceZhang.WCF.DocumentsExplorerDataContract
{  
    [DataContract]
    public class Document
    {
        //DataMembers
    }
}
namespace BruceZhang.WCF.DocumentsExplorerDataContract
{
    [KnownType(typeof(Document))]   
    [CollectionDataContract]
    public class DocumentList:IList<Document>
    {
        //IList<Document> Methods
    }
}

Note that the above definition of the service contract, the service class and data contract namespace.

1, self-managed hosting

ServiceHost <T> Open provided utilizing WCF provided () and Close () method, may facilitate console application developers, Windows application and even ASP.NET application hosting service. No matter what kind of environment from the host application, essentially the way hosting services are the same. For example, in the console application:

using (ServiceHost host = new ServiceHost( typeof(DocumentsExplorerService)))
{
    host.Open();

    Console.WriteLine( "The Service had been launched.");
    Console.Read();
}

Since the ServiceHost instance is created in the application domain, and therefore we must ensure that the host process will not be closed during the call to service, so we use Console.Read () to block the process, so that the console application to run until I think to close the application. If it is a Windows application, you can create the code ServiceHost instance on the main form of the relevant code, to ensure that the service host will not be closed.

Accordingly, we need to configure the application's app.config configuration file:

<configuration>
  <system.serviceModel>
    <services>
      <service name= "BruceZhang.WCF.DocumentsExplorerServiceImplementation.DocumentsExplorerService" behaviorConfiguration= "DocumentExplorerServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress= "http://localhost:8008/DocumentExplorerService"/>
          </baseAddresses>
        </host>         
        <endpoint
          address= ""
          binding= "basicHttpBinding"
          bindingConfiguration= "DocumentExplorerServiceBinding"
          contract= "BruceZhang.WCF.DocumentsExplorerServiceContract.IDocumentsExplorerService"/>
        <endpoint address= "mex" binding= "mexHttpBinding" contract= "IMetadataExchange"/>      
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name= "DocumentExplorerServiceBinding" sendTimeout= "00:10:00" transferMode= "Streamed"
                  messageEncoding= "Text" textEncoding= "utf-8" maxReceivedMessageSize= "9223372036854775807">         
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name= "DocumentExplorerServiceBehavior">
          <serviceMetadata httpGetEnabled= "true"/>         
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Note that the configuration file must contain the name of the service namespace service contracts and service class. In addition, in the configuration file by I <baseAddresses> tag is added to the base address of the service, so the endpoint, address as "."

In this case, the client calls the service profile should also be consistent with the configuration of services:

<configuration>
  <system.serviceModel>
    <client>
      <endpoint       
        address= "http://localhost:8008/DocumentExplorerService"
        binding= "basicHttpBinding"
        bindingConfiguration= "DocumentExplorerServiceBinding"
        contract= "IDocumentsExplorerService"/>
      </client>
    <bindings>
      <basicHttpBinding>
        <binding name= "DocumentExplorerServiceBinding" sendTimeout= "00:10:00" transferMode= "Streamed"
                  messageEncoding= "Text" textEncoding= "utf-8" maxReceivedMessageSize= "9223372036854775807">
        </binding>
      </basicHttpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Note that both profiles of the service address are the same for binding configurations are basically the same.

In a typical enterprise application, we rarely host mode using a self-hosted service, because in this way must be in the running application, the client will be able to call the service, and is not easy to start and stop the service at any time. In addition to not have the ease of use and manageability addition, subject to many restrictions in many aspects of reliability, performance and so on. But because it is simple, easy to implement, therefore, often used for debugging during development or demonstration environment.

Self-managed hosting support all bindings.

2, Windows Services Host

Windows Services Host completely overcome the shortcomings of self-managed hosting, it's easy to manage easily start or stop the service and after the service fails to re-start the service. We can also by Service Control Manager (Service Control Manager), the service is set to automatic startup mode, eliminating the need for management services. In addition, Windows Services itself also provides a certain amount of security and detection mechanisms and logging mechanisms.

Windows Services Host achieve is very simple. We can create Windows Services project in Visual Studio. After you create a project, you can create a class inherited System.ServiceProcess.ServiceBase Windows service class. Windows service class inherits OnStart ServiceBase class () and OnStop () method to complete the Windows service start and stop. We can override these two methods, enabling and disabling the ServiceHost correspondence into the realization of these two methods. For example DocumentsExplorerWindowsService class we created:

namespace BruceZhang.WCF.DocumentsExplorer
{
    public partial class DocumentsExplorerWindowsService : ServiceBase
    {
        private ServiceHost m_serviceHost = null;

        public static void Main()
        {
            ServiceBase.Run( new DocumentsExplorerWindowsService());
        }

        public DocumentsExplorerWindowsService()
        {
            InitializeComponent();

            ServiceName = "DocumentsExplorerService";
        }

        protected override void OnStart( string[] args)
        {
            if (m_serviceHost != null)
            {
                m_serviceHost.Close();
            }

            m_serviceHost = new ServiceHost( typeof(DocumentsExplorerService));
            m_serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (m_serviceHost != null)
            {
                m_serviceHost.Close();
                m_serviceHost = null;
            }
        }
    }
}

In the Main function, we create a Windows service instance by ServiceBase.Run () static methods and constructors Windows service class, call the ServiceName property specifies the service name ServiceBase class. In rewriting the OnStart () method, we first determine whether ServiceHost instance already exists, if does not exist, create it. ServiceHost example of a method to create self managed hosting the same manner.

In order to complete the creation of ServiceHost instance, we also need to add a app.config configuration file in the project, the contents of the configuration file with exactly the same as before.

If you are using WCF technology in enterprise applications, the best way I think is to host the circumstances Windows Services, especially the operating system is not Vista server. It facilitates management services, to maintain a long period of running the service, but it also supports all of the bindings, and therefore subject to a minimum of restrictions. However, the only disadvantage of this approach is the deployment of a host is relatively complex, must be completed by the installation of the service host .NET provides Installutil.exe tool (which may be accomplished by custom installation package operation).

To complete the installation of the service host, we also need to create its installation program. We can customize the installation of a class, it inherits from System.Configuration.Install.Installer class. Easier way is to support the design provided by the Windows service, directly create an installation class. The method is in service under Windows designer view DocumentsExplorerWindowsService example, by right-click and choose "Add Installer" in the shortcut menu, as shown in Figure II:


Figure II Add Installer

Created by the installer ExplorerServiceInstaller follows:

namespace BruceZhang.WCF.DocumentsExplorer
{
    //It needs be ran at the command mode
    //Type installutil filename to install the windows service
    //Type services.msc to access the Service Control Manager(SCM) and browse the windows services
    //Type installutil /u filename to uninstall the windows service
    [RunInstaller(true)]
    public partial class ExplorerServiceInstaller : Installer
    {
        private ServiceProcessInstaller m_process;
        private ServiceInstaller m_service;

        public ExplorerServiceInstaller()
        {
            InitializeComponent();

            m_process = new ServiceProcessInstaller();
            m_process.Account = ServiceAccount.LocalSystem;
            m_service = new ServiceInstaller();
            m_service.ServiceName = "DocumentsExplorerService";
            Installers.Add(m_process);
            Installers.Add(m_service);
        }
    }
}

In ExplorerServiceInstaller class, ServiceAccount is an enumerated type, may be provided LocalService, LocalSystem, NetworkService and User value. Which, LocalService the least secure, most secure User value requires a valid user account can just install the service.

For the installer can set its properties directly in Design view.

The installer built directly in Windows services centralized, get a exe file after compilation, such as DocumentsExplorer.exe. We then run under the Visual Studio Command Prompt mode the following commands:
installutil DocumentsExplorer.exe
to complete the installation of the service host.

Open the Service Control Manager (you can enter in the Command Prompt mode, open Services.msc), you can see the name DocumentsExplorerService services:


Figure III Service Control Manager

To uninstall the host service, can be unloaded by the / u switch of installutil.

In enterprise applications, we tend to the Windows service to start automatically, you can simplify the administrator's job.

3, IIS hosts (description, examples IIS 6.0)

To use the IIS host, you need to add a svc file for the assembly. We can add svc file by adding a new entry way for the project:


Figure IV add svc file

We can also create a WCF Service application directly to IIS as the host, it automatically creates a svc file, as shown in Figure five:


Figure V create a WCF Service Application

svc file created as shown:


svc file Figure VI created

WCF Service应用程序创建的svc文件以及通过添加新项获得svc文件,自动会创建WCF服务。因此,如果我们希望在svc文件中嵌入WCF服务的代码,则可以采取这种方式。例如:

<% @ ServiceHost Language= "C#" Debug= "true" Service= "BruceZhang.WCF.DocumentsExplorerServiceImplementation.DocumentsExplorerService"%>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.IO;

using BruceZhang.WCF.DocumentsExplorerDataContract;

namespace BruceZhang.WCF.DocumentsExplorerServiceImplementation
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class DocumentsExplorerService : IDocumentsExplorerService
    {
        //Service Implementation
    }
}

上述代码中的@ServiceHost指示符只能是在右键单击svc文件后,在View Marckup中才能够看到。

Svc文件通过@ServiceHost指示符指定它所要托管的服务,此外还指定了实现服务的语言、调用模式,还可以设置CodeBehind,指定服务代码。不过,在IIS托管中,服务代码或程序集文件受到一定的限制,它只能放在如下的其中一个位置中:
(1)    svc文件的内嵌代码中;
(2)    放在注册于GAC的单独程序集中;
(3)    驻留于应用程序的Bin文件夹内的程序集中(此时,bin文件夹不必include)
(4)    驻留于应用程序的App_Code文件夹的源代码文件中(根据Language的设置,或者为C#或者为VB);

即使我们将服务代码放在应用程序根目录下,或者其它文件夹中,然后通过CodeBehind指定代码的路径,仍然不能托管服务。

如 果服务契约与服务类是通过引用的方式在宿主应用程序中,则我们可以直接创建一个扩展名为.svc的单个文件,然后include到应用程序根目录下,如图六中的HostService.svc,该文件没有关联的cs文件。此时,在Visual Studio中直接打开该文件,并不能编写服务代码,而是指定@ServiceHost即可。

注意,上述方式的IIS宿主只能创建ServiceHost实例,如果是自定义的ServiceHost,则需要通过@ServiceHost的Factory来指定创建自定义ServiceHost的工厂类。例如这样的自定义ServiceHost以及相应的工厂类:

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;

namespace BruceZhang.WCF.DocumentsExplorerIISHost
{
    public class CustomServiceHostFactory : ServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(
           Type serviceType, Uri[] baseAddresses)
        {
            CustomServiceHost customServiceHost =
               new CustomServiceHost(serviceType, baseAddresses);
            return customServiceHost;
        }
    }

    public class CustomServiceHost : ServiceHost
    {
        public CustomServiceHost(Type serviceType, params Uri[]  baseAddresses)
            : base(serviceType, baseAddresses)
        {
        }

        protected override void ApplyConfiguration()
        {
            base.ApplyConfiguration();
        }
    }
}

则@ServiceHost修改为:

<% @ ServiceHost Language= "C#" Debug= "true" Service= "BruceZhang.WCF.DocumentsExplorerServiceImplementation.DocumentsExplorerService" Factory= "BruceZhang.WCF.DocumentsExplorerIISHost.CustomServiceHostFactory"%>

在IIS托管应用程序中,我们需要创建web.config(注意,不是app.config),在<system.serviceModel>节中配置服务的相关内容:

<system.serviceModel>
    <services>
      <service behaviorConfiguration= "DocumentExplorerServiceBehavior"
       name= "BruceZhang.WCF.DocumentsExplorerServiceImplementation.DocumentsExplorerService">
        <endpoint address= "" binding= "basicHttpBinding" bindingConfiguration= "DocumentExplorerServiceBinding"
         contract= "BruceZhang.WCF.DocumentsExplorerServiceContract.IDocumentsExplorerService" />
        <endpoint address= "mex" binding= "mexHttpBinding" contract= "IMetadataExchange" />
      </service>     
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name= "DocumentExplorerServiceBinding" sendTimeout= "00:10:00" transferMode= "Streamed" messageEncoding= "Text" textEncoding= "utf-8" maxReceivedMessageSize= "9223372036854775807">
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name= "DocumentExplorerServiceBehavior">
          <serviceMetadata httpGetEnabled= "true" />
        </behavior>       
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

注 意,这里的配置文件与之前的宿主配置文件有个别的差异,就是没有指定服务的基地址。这是因为IIS托管会自动将svc文件的地址作为服务的基地址,我们无 法在配置文件中自行指定。Svc文件的地址为svc文件在IIS虚拟目录或站点所设置的路径。例如,我们在IIS中创建一个虚拟目录 DocumentsExplorer指向IIS宿主应用程序DocumentsExplorerIISHost,如图七所示:


图七  在IIS站点中为IIS创建虚拟目录

如果站点的属性没有做任何修改,使用默认的端口号,以及Localhost,则访问服务的基地址为http://localhost /DocumentsExplorer/HostService.svc。如果在配置文件的服务endpoint中设置地址为 DocumentsService,如:

<endpoint
address= "DocumentsService"
binding= "basicHttpBinding"
bindingConfiguration= "DocumentExplorerServiceBinding"
    contract= "BruceZhang.WCF.DocumentsExplorerServiceContract.IDocumentsExplorerService" />

则公开服务的地址则为http://localhost/DocumentsExplorer/HostService.svc/DocumentsServic。

通过IIS启动站点后,不需要做任何操作,服务宿主自动会创建ServiceHost实例或者Factory指定的自定义ServiceHost实例。

由于服务地址发生了变化,因此客户端的配置文件也需要做出相应的修改,必须将服务的地址设置为与之对应的地址。其中,服务的基地址为svc文件在IIS中的地址。

IIS 宿主是一种主要的服务托管方式,这是因为它具有易用性、可维护性、安全性、易于部署等多个优势。然而,它却具有一个致命的阿客流斯之踵,那就是它只支持 HTTP协议的传输绑定。特别对于局域网场景下,如果使用IIS宿主,就无法利用TCP传输的高效率,甚至无法使用MSMQ以及Peer to Peer传输。

IIS 7.0(基于Windows Vista和Windows Server 2007)提供的Windows激活服务(WAS)突破了IIS 6.0对于HTTP的依赖。

4、WAS宿主

WAS是IIS 7.0的一部分,但也可以独立地安装与配置。WAS支持所有可用的WCF传输协议、端口与队列。

利用WAS托管服务与IIS宿主托管服务的方法并没有太大的区别,仍然需要创建svc文件,同时在IIS中需要在站点中创建应有程序指向托管应用程序,还可以设置访问服务的别名与应用程序池。

由于WAS诉诸支持所有的绑定,因此此时的服务绑定并不会受到宿主的限制。

本文已在IT168发表:http://tech.it168.com/msoft/2007-12-11/200712111008739.shtml