65.9K
CodeProject 正在变化。 阅读更多。
Home

Windows Communication Foundation (WCF) 集成验证应用程序块简介

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.28/5 (11投票s)

2007年5月5日

7分钟阅读

viewsIcon

93768

downloadIcon

972

一篇关于验证应用程序块与 Windows Communication Foundation (WCF) 集成的文章

Screenshot - WCFVAB1.gif

目录

引言

有多种方法可以验证服务操作的消息和参数。最常见的方法是在每个服务操作的开头编写复杂的代码。尽管这种方法可以帮助您实现目标,但有时它会变得过于复杂难以维护,并且不够灵活,无法通过配置进行控制。您还必须一遍又一遍地重构它,以便在其他服务和操作中执行相同的验证。

Enterprise Library 3.0 中最有趣的包含之一是“验证应用程序块”,它可以让您轻松地将业务对象的验证需求与业务逻辑流程分开,并为您提供在配置中进行配置的灵活性。

验证应用程序块可以与 Windows Forms、ASP.NET 和 Windows Communication Foundation 集成,以便在业务应用程序中更顺畅地采用。本文将讨论验证应用程序块与 Windows Communication Foundation 之间的集成。

本文假定您对 Windows Communication Foundation 有一定的背景知识,并且熟悉验证应用程序块的基本概念。

验证 WCF 服务消息和参数

在服务操作上验证参数

如果您的服务操作接收原始类型的参数,例如

[ServiceContract]
public interface IOrdersService
{
    [OperationContract]
    int CreateOrder(string currency, double amount);
}

并且您想验证它们,可以在服务协定中使用参数级别的验证

[ServiceContract]
public interface IOrdersService
{
    [OperationContract]
    int CreateOrder(
        [NotNullValidator] string currency,
        [RangeValidator(1.0, RangeBoundaryType.Inclusive, 2.0, 
                RangeBoundaryType.Inclusive)] double amount);
}

请注意,在服务操作的每个参数之前使用了验证属性。这些属性指定了参数的验证要求,并将在运行时由验证应用程序块使用。

验证传递给服务操作的消息协定或数据协定

如果您的服务操作接收“数据协定”参数或“消息协定”参数,则实际上使用为它们指定的验证逻辑。例如,这是一个订单数据的 Data Contract,其中包含验证逻辑,可确保输入的货币是预定义值域之一。

[DataContract]
public class OrderData
{
    [DataMember]
    public double Amount
    {
        get { return amount; }
        set { amount = value; }
    }

    [DataMember]
    [DomainValidator("USD","EUR","JPY")]
    public string Currency
    {
        get { return currency; }
        set { currency = value; }
    }
}

现在,当您在服务协定定义中使用它时,您无需为输入参数指定验证,因为它将从数据协定定义中获取。

[OperationContract]
OrderInfo CreateOrder(OrderData orderData);

请记住,为了验证对象,使用属性并不是唯一的方法。如果您需要更大的灵活性,可以使用配置文件。使用配置文件声明类型和对象的验证逻辑超出了本文的范围。

使用验证行为扩展服务协定

正如我稍后将详细讨论的,“验证应用程序块”对 WCF 的扩展是通过 ValidationBehavior 实现的。WCF 行为是一种控制服务、终结点、特定操作或客户端的各种运行时方面的组件,可以通过属性或配置进行配置。验证行为也是如此。

使用属性配置验证

一种为服务添加验证行为的方法是将 [ValidationBehavior] 属性放在服务协定上方。此属性会在每个操作的运行时定义中添加一个 ValidationParametersInspector ,以便在每次调用服务操作时执行。

[ServiceContract]
[ValidationBehavior]
public interface IOrdersService
{
    ...
}

使用配置文件配置验证

为了配置验证应用程序块对 WCF 的扩展,您应该做的第一件事是在 system.serviceModel 部分声明验证行为扩展

<configuration>
  <system.serviceModel>

    <extensions>
      <behaviorExtensions>
        <add name="validation"
             type="Microsoft.Practices.EnterpriseLibrary.
            Validation.Integration.WCF.ValidationElement, 
            Microsoft.Practices.EnterpriseLibrary.Validation.
            Integration.WCF, Version=3.0.0.0, Culture=neutral, 
            PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>

  </system.serviceModel>
</configuration>

配置文件中的此声明允许您配置一个终结点行为,该行为使用该扩展中指定的配置元素中的定义。在我们的例子中,这是 ValidationElement,它有两个属性:enabled true/false)和 ruleset string)。

此终结点行为的定义将如下所示

<configuration>
  <system.serviceModel>

    <behaviors>
      <endpointBehaviors>
        <behavior name="Validation">
          <validation enabled="true" ruleset="myruleset"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>

虽然使用 [ValidationBehavior] 属性会为服务添加服务级别的行为,但使用配置方法会添加终结点级别的行为。这样,如果您为服务公开了多个终结点,您就可以更灵活地更改终结点之间的验证规则,但基本上,这两种方法的实际效果是相同的。

为了将终结点与上述行为关联起来,您必须在终结点定义中添加 behaviorConfiguration 属性。

这是一个完整的配置片段,显示了为了将验证添加到服务终结点所需的配置。

<configuration>
  <system.serviceModel>

    <extensions>
      <behaviorExtensions>
        <add name="validation"
             type="Microsoft.Practices.EnterpriseLibrary.Validation.
                    Integration.WCF.ValidationElement,
                   Microsoft.Practices.EnterpriseLibrary.Validation.
                            Integration.WCF,
                  Version=3.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>

  </system.serviceModel>
</configuration>

<configuration>
  <system.serviceModel>

    <behaviors>
      <endpointBehaviors>
        <behavior name="Validation">
          <validation enabled="true" ruleset="myruleset"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>

  </system.serviceModel>
</configuration>

<configuration>
  <system.serviceModel>
    <services>
      <service name="Bursteg.Samples.WCFIntegration.Services.OrdersService">

        <endpoint address="https://:8080/OrdersService"
                  binding="basicHttpBinding"
                  behaviorConfiguration="Validation"
                  contract="Bursteg.Samples.WCFIntegration.
                ServiceContracts.IOrdersService" />
      </service>
    </services>

    <behaviors>
      <endpointBehaviors>
        <behavior name="Validation">
          <validation enabled="true" ruleset="myruleset"/>
        </behavior>
      </endpointBehaviors>

    <extensions>
      <behaviorExtensions>
        <add name="validation"
            type="Microsoft.Practices.EnterpriseLibrary.Validation.
            Integration.WCF.ValidationElement, 
            Microsoft.Practices.EnterpriseLibrary.Validation.
            Integration.WCF, Version=3.0.0.0, Culture=neutral, 
            PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>

  </system.serviceModel>
</configuration>

参数无效时的返回值

验证应用程序块检查器会拦截对服务操作的调用,并执行验证传递给该操作的参数的逻辑。如果参数无效,实际的服务操作将永远不会执行,而是会向客户端抛出异常(实际上是 Fault)。

验证结果

使用标准代码验证对象时,我们通常使用以下代码片段。我们验证目标对象,接收一个 ValidationResults 对象,该对象包含由在此验证中执行的验证器返回的验证结果列表。

Validator validator = ValidationFactory.CreateValidator<orderdata />();
ValidationResults results = validator.Validate(myOrderData);
foreach (ValidationResult result in results)
{
    ...
}

对于 WCF 服务,情况略有不同,因为我们不主动执行对象验证,而是由 WCF 组件的验证应用程序块集成来执行。如果参数无效,此组件将抛出 FaultException<ValidationFault>,该异常将在网络上传输为 Soap Fault。ValidationFault 类(类似于 ValidationResults)包含一个 ValidationDetails 项数组,这些项类似于 ValidationResult 项,包含验证消息、键和标签。

WCF 故障处理是一个基本主题,应该熟悉它,它不是本文的一部分,但重要的是要提到,如果您想在客户端捕获此异常并获取有关验证错误的详细信息,您需要做两件事

  1. 为每个附加了验证(或其参数)的服务操作指定 FaultContract 属性,并将 ValidationFault 类作为故障类型

    [ServiceContract]
    public interface IOrdersService
    {
        [FaultContract(typeof(ValidationFault))]
        [OperationContract]
        OrderInfo CreateOrder(OrderData orderData);
    }
    

  2. 使用以下代码捕获验证异常并检查验证详细信息。

    try
    {
        // Call the service operation
    }
    catch (FaultException<ValidationFault> ex)
    {
        // Extract the Detail node from the Fault Exception. 
        // This details is the
        // ValidationFault class
        ValidationFault fault = ex.Detail;
    
        // Iterate through the list of validation errors
        Console.WriteLine("Fault Occurred:");
        foreach (ValidationDetail validationResult in faults.Details)
        {
            Console.WriteLine(string.Format("Message={0} Key={1} Tag={2}",
                validationResult.Message, validationResult.Key, 
                        validationResult.Tag));
        }
    }
    

WCF 可扩展性

参数检查器

WCF 在其各个层都有许多可扩展点。您可以扩展服务模型、通道层、消息层等。扩展 WCF 的一种方法是使用“参数检查器”。参数检查器允许在调用客户端或服务上的操作之前和之后检查或修改信息。为了实现参数检查器,应该实现 IParameterInspector Interface

public interface IParameterInspector
{
    void AfterCall(string operationName, object[] outputs, 
            object returnValue, object correlationState);
    object BeforeCall(string operationName, object[] inputs);
}

操作描述

在不深入讨论细节的情况下,WCF 会区分操作、协定和终结点的静态描述以及它们的运行时定义。当您在客户端创建代理或在服务器上创建服务主机时,WCF 会构建协定、操作和终结点的运行时描述。在创建运行时描述期间,会添加所有行为和扩展。

您可以使用以下代码来获取要向其添加参数检查器的 OperationDescription 的引用,并在运行时查看其属性的值

public OperationDescription GetOperationDescription(Type contractType, 
                            string operationName)
{
    ContractDescription contract = new ContractDescription(contractType.Name);
    OperationDescription operation = new OperationDescription
                        (operationName, contract);
    operation.SyncMethod = contractType.GetMethod(operationName);
    return operation;
}

获得 OperationDescription 后,您可以创建一个 ValidationParameterInspector 的实例

ValidationParameterInspector validationInspector = 
        new ValidationParameterInspector(operation, "myRuleset");

现在,您可以测试服务操作的验证,而无需使用客户端

try
{
    // Create the data contract parameter to pass to the operation
    OrderData orderData = new OrderData();
    orderData.Amount = 3.0;
    orderData.Currency = "ASD";

    validationInspector.BeforeCall("CreateOrder", new object[] { orderData });
}
catch (FaultException<ValidationFault> e)
{
    ValidationFault fault = e.Detail;
    DisplayFault(fault);
}

您应该知道的一件事是,ValidationParameterInspector 仅在 BeforeCall 方法中实现(这是有道理的...),因此您不应该测试 AfterCall 方法。

验证行为

正如我在之前的帖子中提到的,您可以使用 ValidationBehavior 属性放在服务协定上方,以告知 WCF 运行时添加验证行为。此行为实现了 IEndpointBehavior IContractBehavior interfaces,将扩展应用于运行时服务协定和终结点描述。就验证应用程序块而言,此行为会添加上述参数检查器。

使用代码

本文包含一个使用 WCF 验证应用程序块扩展的示例项目。它展示了参数级别和消息级别的验证,并包含了运行示例进行验证所需的配置。这是开始体验本文讨论主题的一个好地方。

Screenshot - WCFVAB2.gif

结论

在 WCF 中使用验证应用程序块可以减少我们需要编写多少代码来验证服务消息。它将验证逻辑与业务逻辑分离,并使我们能够通过配置文件灵活地控制验证。在本文中,我描述了 Windows Communication Foundation 的验证应用程序块扩展。我讨论了参数级别和消息级别的验证,以及如何在服务协定或终结点中通过代码或配置启用验证。

历史

  • 2007 年 4 月 14 日 – 创建
© . All rights reserved.