如何:检索元数据并实现兼容服务

通常,设计和实现服务并不是由同一个人完成的。 在交互操作应用程序很重要的环境中,可以用 Web 服务描述语言 (WSDL) 设计或描述协定,而且开发人员必须实现一个与所提供的协定相兼容的服务。 你可能还需要将现有服务迁移到 Windows Communication Foundation (WCF),但保留传输格式。 此外,双工协定还需要调用方实现一个回调协定。

在这些情况下,必须使用 ServiceModel 元数据实用工具 (Svcutil.exe)(或等效工具)通过可以实现的托管语言生成服务协定接口,以满足协定的要求。 通常情况下,ServiceModel 元数据实用工具 (Svcutil.exe) 用于获取服务协定,该服务协定与通道工厂或 WCF 客户端类型以及设置正确的绑定和地址的客户端配置文件一起使用。 若要使用生成的配置文件,则必须将其更改到服务配置文件中。 您可能还需要修改服务协定。

检索数据并实现兼容服务

  1. 对元数据文件或元数据终结点使用 ServiceModel 元数据实用工具 (Svcutil.exe) 以生成代码文件。

  2. 搜索输出代码文件中包含相关接口的部分(以防存在多个接口),此接口是用 System.ServiceModel.ServiceContractAttribute 属性标记的。 下面的代码示例演示由 ServiceModel 元数据实用工具 (Svcutil.exe) 生成的两个接口。 第一个 (ISampleService) 是服务协定接口,实现它可创建兼容服务。 第二个 (ISampleServiceChannel) 是帮助器接口,客户端使用它可同时扩展服务协定接口和 System.ServiceModel.IClientChannel,且该接口可用于客户端应用程序。

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(
      Namespace="http://microsoft.wcf.documentation"
    )]
    public interface ISampleService
    {
    
        [System.ServiceModel.OperationContractAttribute(
          Action="http://microsoft.wcf.documentation/ISampleService/SampleMethod",
          ReplyAction="http://microsoft.wcf.documentation/ISampleService/SampleMethodResponse"
        )]
        [System.ServiceModel.FaultContractAttribute(
          typeof(microsoft.wcf.documentation.SampleFault),
          Action="http://microsoft.wcf.documentation/ISampleService/SampleMethodSampleFaultFault"
        )]
        string SampleMethod(string msg);
    }
    
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    public interface ISampleServiceChannel : ISampleService, System.ServiceModel.IClientChannel
    {
    }
    
  3. 如果 WSDL 未指定所有操作的答复操作,则生成的操作协定可能会将 ReplyAction 属性设置为通配符 (*)。 移除该属性设置。 否则,当您实现服务协定元数据时,将不能为这些操作导出元数据。

  4. 实现类上的接口并承载服务。 有关示例,请参阅如何:实现服务协定,或参阅下面“示例”一节中的简单实现。

  5. 在由 ServiceModel 元数据实用工具 (Svcutil.exe) 生成的客户端配置文件中,将 <client> 配置节更改为 <services> 配置节。 (有关生成的客户端应用程序配置文件的示例,请参见下面的“示例”部分。)

  6. <services> 配置节中,在服务实现的 <services> 配置节中创建 name 属性。

  7. 将服务的 name 属性设置为服务实现的配置名称。

  8. 将使用实现的服务协定的终结点配置元素添加到服务配置部分。

示例

下面的代码示例演示通过对元数据文件运行 ServiceModel 元数据实用工具 (Svcutil.exe) 而生成的大部分代码文件。

下面的代码演示:

  • 实现时符合协定要求的服务协定接口 (ISampleService)。

  • 客户端所使用的帮助器接口,可用于同时扩展服务协定接口和 System.ServiceModel.IClientChannel,并可用于客户端应用程序 (ISampleServiceChannel)。

  • 扩展 System.ServiceModel.ClientBase<TChannel> 的帮助器类,可用于客户端应用程序 (SampleServiceClient)。

  • 从服务生成的配置文件。

  • 简单的 ISampleService 服务实现。

  • 客户端配置文件到服务器端版本的转换。

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.42
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("http://microsoft.wcf.documentation", ClrNamespace="microsoft.wcf.documentation")]

namespace microsoft.wcf.documentation
{
    using System.Runtime.Serialization;

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
    [System.Runtime.Serialization.DataContractAttribute()]
    public partial class SampleFault : object, System.Runtime.Serialization.IExtensibleDataObject
    {

        private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

        private string FaultMessageField;

        public System.Runtime.Serialization.ExtensionDataObject ExtensionData
        {
            get
            {
                return this.extensionDataField;
            }
            set
            {
                this.extensionDataField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string FaultMessage
        {
            get
            {
                return this.FaultMessageField;
            }
            set
            {
                this.FaultMessageField = value;
            }
        }
    }
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(
  Namespace="http://microsoft.wcf.documentation"
)]
public interface ISampleService
{

    [System.ServiceModel.OperationContractAttribute(
      Action="http://microsoft.wcf.documentation/ISampleService/SampleMethod",
      ReplyAction="http://microsoft.wcf.documentation/ISampleService/SampleMethodResponse"
    )]
    [System.ServiceModel.FaultContractAttribute(
      typeof(microsoft.wcf.documentation.SampleFault),
      Action="http://microsoft.wcf.documentation/ISampleService/SampleMethodSampleFaultFault"
    )]
    string SampleMethod(string msg);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface ISampleServiceChannel : ISampleService, System.ServiceModel.IClientChannel
{
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class SampleServiceClient : System.ServiceModel.ClientBase<ISampleService>, ISampleService
{

    public SampleServiceClient()
    {
    }

    public SampleServiceClient(string endpointConfigurationName) :
            base(endpointConfigurationName)
    {
    }

    public SampleServiceClient(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public SampleServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
    {
    }

    public SampleServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
    {
    }

    public string SampleMethod(string msg)
    {
        return base.Channel.SampleMethod(msg);
    }
}
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ISampleService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                    useDefaultWebProxy="true">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <security mode="None">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="UserName" algorithmSuite="Default" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8080/SampleService" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_ISampleService" contract="ISampleService"
                name="BasicHttpBinding_ISampleService" />
        </client>
    </system.serviceModel>
</configuration>
// Implement the service. This is a very simple service.
class SampleService : ISampleService
{
  public string SampleMethod(string msg)
  {
    Console.WriteLine("The caller said: \"{0}\"", msg);
    return "The service greets you: " + msg;
  }
}
<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_ISampleService" closeTimeout="00:01:00"
            openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
            allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
            maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
            messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
            useDefaultWebProxy="true">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <security mode="None">
            <transport clientCredentialType="None" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="UserName" algorithmSuite="Default" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service
          name="Microsoft.WCF.Documentation.SampleService">
        <endpoint address="http://localhost:8080/SampleService" binding="basicHttpBinding"
            bindingConfiguration="BasicHttpBinding_ISampleService" contract="Microsoft.WCF.Documentation.ISampleService"
            />
      </service>
    </services>
  </system.serviceModel>
</configuration>

另请参阅