WCF Essentials (3)

来源:互联网 发布:中国联通wap网络 编辑:程序博客网 时间:2024/06/05 09:15

6. 端点 (Endpoints)

每个服务都会关联到一个用于定位服务位置的地址(Address),一个用于定义如何与服务进行通讯的绑定(Binding),以及一个告知客户端服务能做什么的契约(Contract),这三样共同组成了服务的助记符 ——ABC。WCF 以端点(Endpoint)这样一个形式来体现三者的关系,端点本身就是地址、契约和绑定的组合体。

uploads/200710/21_203304_1.gif


端点示意图

每个端点都必须完整拥有这三个组成部分,宿主(host)则通过公开端点来对外提供服务。理论上,端点就是服务的外部交互接口、就像 CLR 或者COM接口。每个服务至少需要公开一个端点,服务上所有的端点都必须拥有唯一的定位地址,单个服务可以提供多个端点供不同类型的客户端调用。这些端点可以使用相同或不同的绑定对象,可以拥有相同或不同的服务契约。单个服务的不同端点之间没有任何关联。

端点配置管理

我们可以在宿主配置文件(app.config / web.config)中对端点参数进行设置。

<system.serviceModel>
  <services>
    <service name = "MyNamespace.MyService">
      <endpoint
        address = "http://localhost:8000/MyService/"
        binding = "wsHttpBinding"
        contract = "MyNamespace.IMyContract"
      />
    </service>
  </services>
</system.serviceModel>


需要注意的是,我们必须指定完整的契约限定名(含 Namespace)。当然,我们可以为单个服务提供多个端点设置。

<service name = "MyService">
  <endpoint
    address = "http://localhost:8000/MyService/"
    binding = "wsHttpBinding"
    contract = "IMyContract"
  />
  <endpoint
    address = "net.tcp://localhost:8001/MyService/"
    binding = "netTcpBinding"
    contract = "IMyContract"
  />
  <endpoint
    address = "net.tcp://localhost:8002/MyService/"
    binding = "netTcpBinding"
    contract = "IMyOtherContract"
  />
</service>


在配置文件中设置服务参数是种非常好的选择,它提供了更好的弹性,可以在不修改代码不重新发布系统的情况下对服务的地址、绑定和契约参数进行修改。

我们还可以提供一个或多个默认的基本地址(BaseAddress),这样在端点设置中只需提供相对地址。多个基本地址之间不能冲突,不能在同一个端口进行监听。相对地址通过端点绑定类型与基本地址进行匹配,从而在运行时获得完整地址。如果我们将某个端点设置中的地址设为空值(或省略 address),则表示直接使用某个相匹配的基本地址。

<service name = "MyService">
  <host>
    <baseAddresses>
      <add baseAddress="http://localhost:8080/" />
      <add baseAddress="net.tcp://localhost:8081/" />
    </baseAddresses>
 </host>
 <endpoint
    address = "MyService" <!-- http://localhost:8080/MyService -->
    binding = "wsHttpBinding"
    contract = "IMyContract"
  />
  <endpoint
    address = "MyService" <!-- net.tcp://localhost:8081/MyService -->
    binding = "netTcpBinding"
    contract = "IMyContract"
  />
  <endpoint
    address = "net.tcp://localhost:8002/MyService/"
    binding = "netTcpBinding"
    contract = "IMyOtherContract"
  />
</service>


我们还可以进一步对端点中的绑定参数进行设置。每种绑定类型可拥有多个名称(name)不同的参数设置,然后在端点的 bindingConfiguration 属性中指定关联设置名称即可。

<system.serviceModel>
  <services>
    <service name = "MyService">
      <endpoint
        address = "net.tcp://localhost:8000/MyService/"
        bindingConfiguration = "TransactionalTCP"
        binding = "netTcpBinding"
        contract = "IMyContract"
      />
    </service>
  </services>
  <bindings>
    <netTcpBinding>
      <binding name = "TransactionalTCP"
        transactionFlow = "true"
      />
    </netTcpBinding>
  </bindings>
</system.serviceModel>


下面是一个完整的演示。

[ServiceContract]
interface IMyService
{
  [OperationContract]
  void Test(int x);
}

class MyService : IMyService
{
  public void Test(int x)
  {
    Console.WriteLine(x);
  }
}

class Program
{
  static void Main(string[] args)
  {
    var host = new ServiceHost(typeof(MyService));
    host.Open();

    // ------------
    
    var http = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(),
      new EndpointAddress("http://localhost:801/MyService"));
      
    using (http as IDisposable)
    {
      http.Test(1);
    }

    // ----------------
    
    var tcp = ChannelFactory<IMyService>.CreateChannel(new NetTcpBinding(),
      new EndpointAddress("net.tcp://localhost:802/MyService"));
      
    using (tcp as IDisposable)
    {
      tcp.Test(1);
    }

    Console.WriteLine("Press any key to exit...");
    Console.ReadKey(true);
    Environment.Exit(0);
  }
}


App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Learn.CUI.MyService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:801" />
            <add baseAddress="net.tcp://localhost:802" />
          </baseAddresses>
        </host>
        <endpoint
          address="MyService"
          binding="basicHttpBinding"
          contract="Learn.CUI.IMyService"
        />
        <endpoint
          address="MyService"
          binding="netTcpBinding"
          contract="Learn.CUI.IMyService"
        />
      </service>
    </services>
  </system.serviceModel>
</configuration>


除了使用配置文件外,我们还可以直接在代码中对端点参数进行设置。

ServiceHost host = new ServiceHost(typeof(MyService));

Binding wsBinding = new WSHttpBinding( );
Binding tcpBinding = new NetTcpBinding( );

host.AddServiceEndpoint(typeof(IMyContract), wsBinding, "http://localhost:8000/MyService");
host.AddServiceEndpoint(typeof(IMyContract), tcpBinding, "net.tcp://localhost:8001/MyService");
host.AddServiceEndpoint(typeof(IMyOtherContract), tcpBinding, "net.tcp://localhost:8002/MyService");

host.Open( );


ServiceHost 类型用来创建 Self-Hosting,AddServiceEndpoint(...) 有多个重载方法,用于添加端点设置。

和上面配置文件中所做的一样,在代码里同样可以使用绝对或相对地址。

Uri baseHttpUri = new Uri("http://localhost:8000");
Uri baseTcpUri = new Uri("net.tcp://localhost:8001");

ServiceHost host = new ServiceHost(typeof(MyService), baseHttpUri, baseTcpUri);

Binding wsBinding = new WSHttpBinding( );
Binding tcpBinding = new NetTcpBinding( );

host.AddServiceEndpoint(typeof(IMyContract), wsBinding, "MyService");
host.AddServiceEndpoint(typeof(IMyContract), tcpBinding, "MyService");
host.AddServiceEndpoint(typeof(IMyOtherContract), tcpBinding, "net.tcp://localhost:8002/MyService");

host.Open( );


至于绑定类型的设置,同样没啥问题。

ServiceHost host = new ServiceHost(typeof(MyService));

NetTcpBinding tcpBinding = new NetTcpBinding( );
tcpBinding.TransactionFlow = true;

host.AddServiceEndpoint(typeof(IMyContract), tcpBinding, "net.tcp://localhost:8000/MyService");

host.Open( );
原创粉丝点击