WCF服务编程(4)——以编程的方式配置终结点




一、引言

以编程方式配置终结点(endpoint)比较简单,我们创建ServiceHost对象后,直接调用其AddServiceEndPointAPI,该API原型如下:

public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address);

implementedContract是我们定义的服务契约的类型;binding是我们创建的Binding对象,如使用http传输协议时,我们需要New一个WSHttpBinding对象传到这里,第三个参数就是string类型的uri。

二、终结点的配置

和在配置文件中配置终结点类似,AddServiceEndpoint里面的address共有三种配置方案:

第一种,配置空,表明服务地址为配置的基地址。

host.AddServiceEndpoint(typeof(IService1), wsBinding, "");

第二种,配置某个相对路径字符串,比如如下配置:

 
host.AddServiceEndpoint(typeof(IService1), wsBinding, "MyService");

在客户端配置中配置的终结点地址将会是带上相对路径的uri:

第三种:配置全路径uri,此时服务的路劲将会是全新的这个uri,不再使用基地址。如下我们在服务端这么进行配置的话:

host.AddServiceEndpoint(typeof(IService1), wsBinding, "http://localhost:8002/");

在客户端,配置的终结点路径将是:

http://localhost:8002/

下面是这对最后一种配置客户端配置文件的实例:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8002" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
                name="WSHttpBinding_IService1">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

三、为相同服务配置多个终结点

在同一个服务中,通过编程方式我们可以配置不同的终结点,比如下面的配置:

     

我分别配置了两个wsHttpBinding类型的终结点,分别是:

host.AddServiceEndpoint(typeof(IService1), wsBinding, "");

host.AddServiceEndpoint(typeof(IService1),wsBinding,@"http://localhost:8002/MyService")


此时如果我们再次在客户端引入该服务引用,发现生成的配置文件中也包含这两个终结点:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8001/" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
                name="WSHttpBinding_IService1">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
            <endpoint address="http://localhost:8002/MyService" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
                name="WSHttpBinding_IService11">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

我们运行客户端程序,发现程序异常。我们在客户端引用时不能同时创建两个终结点,否则客户端不知道去调用哪个位置的服务,删除一个后运行正常。

四、默认终结点和协议映射

  当配置文件没有添加终结点以及在代码中也没有配置终结点时,WCF会默认添加这些终结点,也可以在代码中使用ServiceHost的AddDefaultEndpoints来增加默认终结点,如下所示:   

 [STAThread]
        static void Main()
        {
            Uri uri = new Uri(@"http://localhost:8001");
            Uri uri1 = new Uri(@"net.tcp://localhost:8002");
            ServiceHost host = new ServiceHost(typeof(Service1), uri, uri1);
            host.AddDefaultEndpoints();
 
            host.Open();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
            host.Close();
        }


  其中host.AddDefaultEndpoints()这句换可有可无,即使不添加,WCF也会默认生成终结点。在查看生成的终结点之前,我们先看下服务类Service1的定义:

public class Service1 : IService1,IService2
    {
        public void DoWork()
        {
            MessageBox.Show("我ò被?调獭?用?了?");
        }
 
        public void DoOtherWork()
        {
            MessageBox.Show("我ò又?被?调獭?用?了?");
        }
}



发现它实现了两个契约接口,而我们生成的终结点Name将和这两个契约接口有关,下面是生成的四个终结点:

<system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IService1" />
                <binding name="NetTcpBinding_IService2" />
            </netTcpBinding>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" />
                <binding name="WSHttpBinding_IService2" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8001/" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="IService1"
                name="WSHttpBinding_IService1">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
            <endpoint address="http://localhost:8001/" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService2" contract="IService2"
                name="WSHttpBinding_IService2">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
            <endpoint address="net.tcp://localhost:8002/" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IService1" contract="IService1"
                name="NetTcpBinding_IService1">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
            <endpoint address="net.tcp://localhost:8002/" binding="netTcpBinding"
                bindingConfiguration="NetTcpBinding_IService2" contract="IService2"
                name="NetTcpBinding_IService2">
                <identity>
                    <userPrincipalName value="Hyman-PC\Hyman" />
                </identity>
            </endpoint>
        </client>
</system.serviceModel>

可以看到,终结点的命名规则是WCF基地址的scheme推测的绑定类型和契约接口的组合,共生成了4个终结点。通常在默认情况下,WCF推测http的绑定类型是basicHttpBinding,但是在上面的代码中推测出的是WSHttpBinding,这是因为我们在配置文件中设置了协议映射:

<system.serviceModel>
        ...
      <protocolMapping>
        <add scheme="http" binding="wsHttpBinding"/>
      </protocolMapping>
</system.serviceModel>

我们要明白,这里的协议映射是可选的,即使我们不进行设置,WCF也会根据基地址的scheme推测中默认的绑定类型,然后和契约接口组成契约名称。

 



 

 

 

 

 





评论