WCF Essentials (5)

来源:互联网 发布:想开淘宝店怎么注册 编辑:程序博客网 时间:2024/06/12 23:44

8. 元数据交换 (Metadata Exchange)

服务有两种方式来发布元数据。你可以通过 HTTP-GET协议来提供元数据,或者使用专门的 MEX 端点。WCF 可以自动透过 HTTP-GET提供元数据,你要做的全部工作仅仅是显式添加一个服务行为(service behavior) —— serviceMetadata,并将其属性httpGetEnabled 设为 true。

<system.serviceModel>
  <services>
    <service behaviorConfiguration="Metadata" name="MyService">
      <host>
        <baseAddresses>
          <add baseAddress="http://localhost:801/" />
        </baseAddresses>
      </host>
      <endpoint binding="basicHttpBinding" contract="IMyService" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="Metadata">
        <serviceMetadata httpGetEnabled="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>


一旦你允许通过 HTTP-GET交换元数据,那么你可以在网页浏览器中输入基本地址(如果指定了)查看服务的相关信息。你会看到一个服务确认页,其中包含了服务的基本信息,以及如何创建客户端代理的提示。这个确认页与 IIS hosting 无关,Self-hosting 同样可以看到。

uploads/200710/23_145018_1.gif



我们同样可以在编码中指定这种行为。

ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://localhost:801"));

host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "MyService");

ServiceMetadataBehavior metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>( );
if(metadataBehavior == null)
{
  metadataBehavior = new ServiceMetadataBehavior( );
  metadataBehavior.HttpGetEnabled = true;
  host.Description.Behaviors.Add(metadataBehavior);
}

host.Open( );


ServiceMetadataBehavior 还有另外一个属性 HttpGetUrl,以便我们设置一个自定义元数据发布地址(绝对地址或相对地址)。

app.config / web.config

<serviceMetadata httpGetEnabled="true" httpGetUrl="Meatadata" />


metadataBehavior.HttpGetUrl = new Uri("http://localhost:801/Meatadata");


Metadata Exchange Endpoint

服务还可以通过一个名为 "metadata exchange endpoint" 的专用端点来发布元数据,这个端点通常被称之为 "MEX 端点"。MEX 是行业标准的元数据交换格式。

uploads/200710/23_145023_2.gif

 

[ServiceContract(...)]
public interface IMetadataExchange
{
  [OperationContract(...)]
  Message Get(Message request);
  //More members
}


MEX标准的实现复杂而繁琐,幸好 WCF 已经提供了相关的实现,我们只需做些简单的设置即可。使用 MEX 端点并不需要我们打开 HTTP-GET设置,当然也不会起冲突,通常两者会同时存在。下面的例子中,我们提供了三个不同传输协议的 MEX 端点。这些 MEX端点与其它服务端点一样,可以使用绝对路径,或者基于基本地址的相对路径。

<service name = "MyService" behaviorConfiguration = "MEX">
  <host>
    <baseAddresses>
      <add baseAddress = "net.tcp://localhost:8001/"/>
      <add baseAddress = "net.pipe://localhost/"/>
    </baseAddresses>
  </host>
  <endpoint
    address = "MEX"
    binding = "mexTcpBinding"
    contract = "IMetadataExchange"
  />
  <endpoint
    address = "MEX"
    binding = "mexNamedPipeBinding"
    contract = "IMetadataExchange"
  />
  <endpoint
    address = "http://localhost:8000/MEX"
    binding = "mexHttpBinding"
    contract = "IMetadataExchange"
  />
</service>
<behaviors>
  <serviceBehaviors>
    <behavior name = "MEX">
      <serviceMetadata />
    </behavior>
  </serviceBehaviors>
</behaviors>


注意: 包含 MEX 端点的服务必须关联到一个拥有 serviceMetadata 元素的服务行为设置,哪怕 serviceMetadata内部设置为空也不能省略。因为有该元素,宿主才会向 Description.Behaviors 里添加ServiceMetadataBehavior。

和操作其它服务端点一样,我们也可以通过代码来添加 MEX 端点。首先我们向 host 添加 ServiceMetadataBehavior,然后添加一个 MEX 端点。所不同的是,我们必须使用 CustomBinding 来构建该端点所需的绑定对象。

ServiceMetadataBehavior metadataBehavior;
metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
  metadataBehavior = new ServiceMetadataBehavior();
  host.Description.Behaviors.Add(metadataBehavior);
}      

BindingElement bindingElement = new HttpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElement);

host.AddServiceEndpoint(typeof(IMetadataExchange), binding, "MEX");


--------以下是完整演示代码--------------

(1) 配置文件方式演示

app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Learn.CUI.MyService" behaviorConfiguration="MexBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:801/" />
          </baseAddresses>
        </host>
        <endpoint binding="basicHttpBinding" contract="Learn.CUI.IMyService" />
        <endpoint address="MEX" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MexBehavior">
          <serviceMetadata />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>


Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;

namespace Learn.CUI
{
  [ServiceContract]
  public interface IMyService
  {
    [OperationContract]
    void Test();
  }

  public class MyService : IMyService
  {
    public void Test()
    {
    }
  }

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

      Console.ReadKey(true);
    }
  }
}


(2) 代码方式演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;

namespace Learn.CUI
{
  [ServiceContract]
  public interface IMyService
  {
    [OperationContract]
    void Test();
  }

  public class MyService : IMyService
  {
    public void Test()
    {
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      Uri baseAddress = new Uri("http://localhost:801/");
      ServiceHost host = new ServiceHost(typeof(MyService), baseAddress);

      host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");

      ServiceMetadataBehavior metadataBehavior;
      metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
      if (metadataBehavior == null)
      {
        metadataBehavior = new ServiceMetadataBehavior();
        host.Description.Behaviors.Add(metadataBehavior);
      }

      BindingElement bindingElement = new HttpTransportBindingElement();
      CustomBinding binding = new CustomBinding(bindingElement);
      host.AddServiceEndpoint(typeof(IMetadataExchange), binding, "MEX");

      host.Open();

      Console.ReadKey(true);
    }
  }
}
原创粉丝点击