WCF服务编程(2)——自托管服务

一、引言

自托管是由开发者提供和管理宿主进程生命周期的一种方式,简单来理解,自托管就是一种应用程序托管,以Winform、Windows NT服务、控制台程序等为宿主进程,在宿主进程运行时开启托管的WCF服务。不同于IIS托管,自托管支持所有的WCF服务协议,包括http、tcp、UDP等等。

下面的例子,我们在Winform进程之上,进行WCF服务的托管。

二、自托管的两种发布服务的方式

   在自托管中,我们可以通过代码发布和app.config发布两种方式进行服务的发布,前者我们通过在Winform的项目中的Program.cs文件中编写发布代码;后者,我们选中项目,选择添加WCF服务后,会在项目中自动生成一个app.config文件。

1.png 

2.1 利用代码进行发布

在代码发布方式中,我们创建ServiceHost对象来承载我们的服务相关信息,该类的构造函数如下:

public  ServiceHost( Type serviceType,params Uri[] baseAddresses);


serviceType是服务类型,就是我们自定义的服务类。比如在本次我们定义如下服务类:

 public class MyService : IService1
    {
        public void DoWork()
        {
            
        }
    }


那该参数将填写typeof(MyService),后者是Uri组成的数组对象,如果有多个Uri对象直接填写,用逗号隔开即可。值得注意的是一个ServiceHost对象可以托管多种协议的Uri,但是同一种协议的Uri只能有一种。

如下面的例子,我们分别构建了一个tcp协议和http协议的Uri对象,托管到了ServiceHost中:

  Uri tcpBaseAddress = new Uri("net.tcp://localhost:8001/");
  Uri httpBaseAddress = new Uri("http://localhost:8002/");
  ServiceHost host = new ServiceHost(typeof(MyService), httpBaseAddress, tcpBaseAddress);

完成了上述托管之后,我们只需在winform窗口显示之前调用ServiceHostopen方法开启服务,并在窗口关闭之后,调用ServiceHostclose方法关闭服务即可。

  static void Main()
  {
      Uri tcpBaseAddress = new Uri("net.tcp://localhost:8001/");
      Uri httpBaseAddress = new Uri("http://localhost:8002/");
 
      ServiceHost host = new ServiceHost(typeof(MyService), httpBaseAddress, tcpBaseAddress);
          
      host.Open();
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Application.Run(new Form1());
      host.Close();
  }

 开启服务之后,我们可以直接在客户端中添加上面定义的Uri即可连接服务。   

2.png 

使用代码托管时,对于http协议的服务,有时会出现端口权限的问题,导致服务开启不成功,此时有两种解决方法:

一是使用管理员权限运行程序;

二是利用netsh为http预留相关的端口,比如要预留上述8002的端口,我们可以在cmd中进行如下设置:

Netsh http add urlacl url=http://+8002/  user=”everyone”

2.2 利用app.config进行发布

利用app.config进行服务的发布,类似于IIS托管中的Web.config,如下所示。Service中配置的name属性为我们定义的服务类,而baseAddresses中配置的是服务的全地址uri,这点和IIS的Web.config有所不同,Web.config中配置的是相对地址。

<services>
    <service name="WindowsFormsApplication3.MyService">
        <endpoint address="" binding="wsHttpBinding" contract="WindowsFormsApplication3.IService1">
               <identity>
                        <dns value="localhost" />
               </identity>
         </endpoint>
         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:8732/Design_Time_Addresses/WindowsFormsApplication3/Service1/" />
                    </baseAddresses>
                  <timeouts closeTimeout="00:00:20"/>
                </host>
    </service>
</services>


需要注意的是,我们在同时配置代码发布和app.config两种发布方式时,宿主会集成两种方式中配置的所有的服务Uri,但是服务协议不能重复,否则就会报错。

 

三、自托管的一些高级特性

HostService对象还有一些高级特性,比如支持异步打开和关闭服务的BeginOpen()BeginClose()方法。

BeginOpen原型如下:

public  IAsyncResult  BeginOpen( TimeSpan timeout, AsyncCallback callback, object state);


它的第一个参数是一个TimeSpan对象,用来指定超时;第二个参数是一个委托,可以传入形如以下方法前面的回调函数,在这个方法中我们可以在打开服务成功后做一些其他操作,第三个参数用来记录宿主的状态:

void SomeMethod(IAsyncResult ar);


 

 

 

 

 


评论