WCF 客户端概述

本部分介绍客户端应用程序执行的作、如何配置、创建和使用 Windows Communication Foundation (WCF) 客户端,以及如何保护客户端应用程序。

使用 WCF 客户端对象

客户端应用程序是一个托管应用程序,它使用 WCF 客户端与其他应用程序通信。 为 WCF 服务创建客户端应用程序需要以下步骤:

  1. 获取服务终结点的服务协定、绑定和地址信息。

  2. 使用该信息创建 WCF 客户端。

  3. 调用操作。

  4. 关闭 WCF 客户端对象。

以下部分将讨论这些步骤,并简要介绍以下问题:

  • 处理错误。

  • 配置和保护客户端。

  • 为双工服务创建回调对象。

  • 异步调用服务。

  • 使用客户端通道调用服务。

获取服务协定、绑定和地址

在 WCF 中,服务和客户端使用托管属性、接口和方法建模协定。 若要连接到客户端应用程序中的服务,需要获取服务协定的类型信息。 通常,使用 ServiceModel 元数据实用工具工具(Svcutil.exe)获取服务协定的类型信息。 该实用工具从服务下载元数据,以所选语言将其转换为托管源代码文件,并创建可用于配置 WCF 客户端对象的客户端应用程序配置文件。 例如,如果要创建一个 WCF 客户端对象来调用 MyCalculatorService,并且你知道该服务的元数据已发布在 http://computerName/MyCalculatorService/Service.svc?wsdl,那么以下代码示例展示了如何使用 Svcutil.exe 获取包含托管代码中服务契约的 ClientCode.vb 文件。

svcutil /language:vb /out:ClientCode.vb /config:app.config http://computerName/MyCalculatorService/Service.svc?wsdl  

可以将此协定代码编译到客户端应用程序中,也可以编译为客户端应用程序随后可用于创建 WCF 客户端对象的另一个程序集。 可以使用配置文件配置客户端对象以正确连接到服务。

有关此过程的示例,请参阅 “如何:创建客户端”。 有关合同的详细信息,请参阅 “合同”。

创建 WCF 客户端对象

WCF 客户端是一个本地对象,它以客户端可用于与远程服务通信的形式表示 WCF 服务。 WCF 客户端类型实现目标服务协定,因此在创建一个并对其进行配置时,可以直接使用客户端对象调用服务作。 WCF 运行时将方法调用转换为消息,将其发送到服务,侦听答复,并将这些值作为返回值或参数outref返回到 WCF 客户端对象。

还可以使用 WCF 客户端通道对象来连接和使用服务。 有关详细信息,请参阅 WCF 客户端体系结构

创建新的 WCF 对象

为了说明类的使用 ClientBase<TChannel> ,假设已从服务应用程序生成以下简单的服务协定。

注释

如果使用 Visual Studio 创建 WCF 客户端,则向项目添加服务引用时,对象会自动加载到对象浏览器中。

[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);
}

如果不使用 Visual Studio,请检查生成的协定代码以查找扩展 ClientBase<TChannel> 的类型和服务协定接口 ISampleService。 在这种情况下,该类型类似于以下代码:

[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);
    }
}

可以通过使用其中一个构造函数将此类创建为一个本地对象,并对该本地对象进行配置,然后使用它连接到 ISampleService 类型的服务。

建议先创建 WCF 客户端对象,然后在单个 try/catch 块内使用它并将其关闭。 请勿使用 using 语句(Using 在 Visual Basic 中),因为它可以在某些失败模式下屏蔽异常。 有关详细信息,请参阅以下部分,以及 使用 Close 和 Abort 释放 WCF 客户端资源

协定、绑定和地址

必须先配置客户端对象,然后才能创建 WCF 客户端对象。 具体而言,它必须具有一个服务终结点以供使用。 终结点由服务协定、绑定和地址组成。 (有关终结点的详细信息,请参阅 终结点:地址、绑定和协定。通常,此信息位于 <客户端应用程序配置文件中的终结点> 元素中,例如 Svcutil.exe 工具生成的终结点元素,并在创建客户端对象时自动加载。 这两种 WCF 客户端类型还具有重载,使你能够以编程方式指定此信息。

例如,用于之前示例中的 ISampleService 的生成配置文件包含以下端点信息。

<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_ISampleService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:01:00" sendTimeout="00:01:00"
                    bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                    maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                    messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                    allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Message">
                        <transport clientCredentialType="None" proxyCredentialType="None"
                            realm="" />
                        <message clientCredentialType="Windows" negotiateServiceCredential="true"
                            algorithmSuite="Default" establishSecurityContext="true" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8080/SampleService" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_ISampleService" contract="ISampleService"
                name="WSHttpBinding_ISampleService">
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

此配置文件在<client>元素中指定了一个目标端点。 有关使用多个目标终结点的详细信息,请参阅 ClientBase<TChannel>ChannelFactory<TChannel> 构造函数。

调用操作

创建并配置了客户端对象后,请创建一个 try/catch 块,如果该对象是本地对象,则以相同的方式调用操作,然后关闭 WCF 客户端对象。 当客户端应用程序调用第一个操作时,WCF 会自动打开底层通道,并在对象被回收时关闭底层通道。 (或者,也可以在调用其他操作之前或之后,显式地打开和关闭通道。)

例如,如果你有以下服务协定:

namespace Microsoft.ServiceModel.Samples  
{  
    using System;  
    using System.ServiceModel;  
  
    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]  
    public interface ICalculator  
   {  
        [OperationContract]  
        double Add(double n1, double n2);  
        [OperationContract]  
        double Subtract(double n1, double n2);  
        [OperationContract]  
        double Multiply(double n1, double n2);  
        [OperationContract]  
        double Divide(double n1, double n2);  
    }  
}  
Namespace Microsoft.ServiceModel.Samples  
  
    Imports System  
    Imports System.ServiceModel  
  
    <ServiceContract(Namespace:= _  
    "http://Microsoft.ServiceModel.Samples")> _
   Public Interface ICalculator  
        <OperationContract> _
        Function Add(n1 As Double, n2 As Double) As Double  
        <OperationContract> _
        Function Subtract(n1 As Double, n2 As Double) As Double  
        <OperationContract> _
        Function Multiply(n1 As Double, n2 As Double) As Double  
        <OperationContract> _
     Function Divide(n1 As Double, n2 As Double) As Double  
End Interface  

可以通过创建 WCF 客户端对象并调用其方法来调用作,如下面的代码示例所示。 WCF 客户端对象的打开、调用和关闭发生在单个 try/catch 块中。 有关详细信息,请参阅 使用 WCF 客户端访问服务并使用 Close 和 Abort 释放 WCF 客户端资源

CalculatorClient wcfClient = new CalculatorClient();
try
{
    Console.WriteLine(wcfClient.Add(4, 6));
    wcfClient.Close();
}
catch (TimeoutException timeout)
{
    // Handle the timeout exception.
    wcfClient.Abort();
}
catch (CommunicationException commException)
{
    // Handle the communication exception.
    wcfClient.Abort();
}

处理错误

在客户端应用程序中,当打开底层客户端通道(无论是通过显式调用还是自动调用)、使用客户端或通道对象调用操作或关闭底层客户端通道时,可能会出现异常。 建议应用程序至少处理可能的 System.TimeoutExceptionSystem.ServiceModel.CommunicationException 异常,以及由于操作返回的 SOAP 错误而引发的任何 System.ServiceModel.FaultException 对象。 操作协定中指定的 SOAP 错误将作为 System.ServiceModel.FaultException<TDetail> 在客户端应用程序中引发,此异常中的类型参数为 SOAP 错误的详细信息类型。 有关在客户端应用程序中处理错误条件的详细信息,请参阅 发送和接收错误。 有关演示如何在客户端处理错误的完整示例,请参阅预期异常

配置和保护客户端

配置客户端从客户端或通道对象所需的目标终结点信息加载开始,通常是从配置文件加载,不过还可以使用客户端构造函数和属性以编程方式加载此信息。 但是,为启用某些客户端行为和许多安全方案,需要执行其他配置步骤。

例如,服务协定的安全要求在服务协定接口中声明,如果 Svcutil.exe 创建了配置文件,则该文件通常包含一个能够支持服务安全要求的绑定。 但在某些情况下,可能需要更多安全配置,例如配置客户端凭据。 有关 WCF 客户端安全配置的完整信息,请参阅 “保护客户端”。

此外,可以在客户端应用程序中启用某些自定义修改,例如自定义运行时行为。 有关如何配置自定义客户端行为的详细信息,请参阅 “配置客户端行为”。

为双工服务创建回调对象

双工服务指定一个回调协定,客户端应用程序必须实现该协定以便提供一个该服务能够根据协定要求调用的回调对象。 尽管回调对象不是完整的服务(例如,不能使用回调对象启动通道),但出于实现和配置的目的,可以将其视为一种服务。

双工服务的客户端必须:

  • 实现一个回调协定类。

  • 创建回调协定实现类的实例,并使用它来创建 System.ServiceModel.InstanceContext 传递给 WCF 客户端构造函数的对象。

  • 调用操作并处理操作回调。

双工 WCF 客户端对象除了会公开支持回调所必需的功能(包括回调服务的配置)以外,其他的功能和它们的非双工对应项相同。

例如,可以使用回调类的属性来控制回调对象运行时行为的 System.ServiceModel.CallbackBehaviorAttribute 方方面面。 另一个示例是使用该 System.ServiceModel.Description.CallbackDebugBehavior 类将异常信息返回给调用回调对象的服务。 有关详细信息,请参阅双工服务。 有关完整示例,请参阅双工

在运行 Internet Information Services (IIS) 5.1 的 Windows XP 计算机上,双向通讯客户端必须使用 System.ServiceModel.WSDualHttpBinding 类指定客户端基址,否则将引发异常。 下面的代码示例演示如何在代码中执行此作。

WSDualHttpBinding dualBinding = new WSDualHttpBinding();
EndpointAddress endptadr = new EndpointAddress("http://localhost:12000/DuplexTestUsingCode/Server");
dualBinding.ClientBaseAddress = new Uri("http://localhost:8000/DuplexTestUsingCode/Client/");

Dim dualBinding As New WSDualHttpBinding()
Dim endptadr As New EndpointAddress("http://localhost:12000/DuplexTestUsingCode/Server")
dualBinding.ClientBaseAddress = New Uri("http://localhost:8000/DuplexTestUsingCode/Client/")

以下代码演示如何在配置文件中执行此作

<client>
  <endpoint
    name ="ServerEndpoint"
    address="http://localhost:12000/DuplexUsingConfig/Server"
    bindingConfiguration="WSDualHttpBinding_IDuplex"
    binding="wsDualHttpBinding"
    contract="IDuplex"
/>
</client>
<bindings>
  <wsDualHttpBinding>
    <binding
      name="WSDualHttpBinding_IDuplex"
      clientBaseAddress="http://localhost:8000/myClient/"
    />
  </wsDualHttpBinding>
</bindings>

异步调用服务

操作的调用方式完全由客户端开发人员决定。 这是因为在托管代码中表示时,构成操作的消息可以映射到同步或异步方法。 因此,如果您想构建一个异步调用操作的客户端,可以使用 Svcutil.exe 选项来生成异步客户端代码 /async。 有关详细信息,请参阅如何:以异步方式调用服务操作

通过 WCF 客户端通道进行服务调用

WCF 客户端类型扩展 ClientBase<TChannel>,而 ClientBase<TChannel> 本身派生自 接口,以提供对底层通道系统的访问。 可以同时使用目标服务协定和 System.ServiceModel.ChannelFactory<TChannel> 类来调用服务。 有关详细信息,请参阅 WCF 客户端体系结构

另请参阅