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

集成验证块与 WCF

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2011年9月23日

CPOL

4分钟阅读

viewsIcon

43406

downloadIcon

1103

介绍如何在 Microsoft Enterprise Library 5.0 中集成和使用验证块功能,并将其与 WCF 结合使用。

引言

验证块用于验证目的,并支持特定于技术的集成功能,如 WPF 和 WCF。 与大多数技术提供的验证方法相比,它提供了一种简单且相对简单的方式来验证数据。 我将重点介绍如何在 Microsoft Enterprise Library 5.0 中将验证块与 WCF 集成。

您可以从以下文章中了解什么是验证块以及如何在您的项目中使用它:Microsoft Enterprise Library 5.0 - 验证块介绍

背景

WCF 通过实现 IParameterInspector 接口来采用其自己的验证方法。 您可以从以下地址找到一篇好文章,展示了如何使用 IParameterInspector 接口进行验证:如何:在 WCF 中执行输入验证

实际上,这种方法需要更多的精力,并且提供了比验证块更复杂的方法。 通过验证块,您只需关注要验证的内容,而不是如何验证。 这使得验证块更具吸引力。 此外,它还可以避免您编写自己的验证和维护的复杂性。

如何配置

虽然它可以避免复杂性,但我梦想有一种没有配置的技术,但好消息是,您只需要将以下设置放入 WCF 的配置中即可。

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="validation"
             type="Microsoft.Practices.EnterpriseLibrary.
                    Validation.Integration.WCF.ValidationElement, 
                  Microsoft.Practices.EnterpriseLibrary.
                    Validation.Integration.WCF, 
                  Version=5.0.414.0, 
                  Culture=neutral, 
                  PublicKeyToken=31bf3856ad364e35" />
      </behaviorExtensions>
    </extensions>
	.......
</system.serviceModel>

在移植所需的设置后,我们需要再执行一个步骤才能启动。 除了验证和通用程序集之外,我们还需要将 Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF 添加为项目的引用。

这是引用的结构

References of WCF project

开发我们的项目

我开发了一个 WCF 服务和一个客户端 WPF 应用程序。 WPF 应用程序将把 UI 中的数据发送到 WCF 服务,并检查结果。

这是项目结构

Project structure

在配置和构建项目结构之后,我们可以编写 WCF 服务和 WPF 应用程序。 让我们从服务部分开始。

服务端

在服务端,我们创建一个名为 SalaryService 的服务。 此服务公开两种方法:CalculatePartialCalculateFull。 这两种方法实际上做的事情相同,但方式不同。

[ServiceContract]
[ValidationBehavior]
public interface ISalaryService
{
    // This method is validated partially
    // We assume that the client uses proxy to communicate
    // with the service so we do not need to validate the property types
    [OperationContract]
    [FaultContract(typeof(ValidationFault))]
    string CalculatePartial(
                
        [RangeValidator(2, RangeBoundaryType.Inclusive, 5, 
          RangeBoundaryType.Inclusive, 
          MessageTemplate = 
            "Education level must be between {3} and {5}")]
        int EducationLevel,
            
        [RangeValidator(0, RangeBoundaryType.Inclusive, 30, 
          RangeBoundaryType.Inclusive, 
          MessageTemplate = 
            "Your experience in years must be between {3} and {5}")]
        int ExperienceInYears,

        [NotNullValidator(MessageTemplate = 
                          "You must supply your currency")]
        [StringLengthValidator(1, RangeBoundaryType.Inclusive, 3, 
          RangeBoundaryType.Inclusive, 
          MessageTemplate = 
            "Currency code must be between {3} and {5} characters.")]
        string Currency,
            
        bool HasCertificate,
            
        bool InvolvedInManagement
    );

    // This method is validated fully
    // We check all conditions to make sure that
    // the input is totally right using Validation Block
    [OperationContract]
    [FaultContract(typeof(ValidationFault))]
    string CalculateFull(
                
        // EducationLevel is not null, it is parsed
        // to Int as correctly, and it is between 2 and 5
        [NotNullValidator(MessageTemplate = 
                "You must supply your education level")]
        [TypeConversionValidator(typeof(int), 
          MessageTemplate = 
            "You must supply a valid level of your education")]
        [RangeValidator("2", RangeBoundaryType.Inclusive, "5", 
          RangeBoundaryType.Inclusive, 
          MessageTemplate = 
            "Education level must be between {3} and {5}")]
        string EducationLevel,
            
        [NotNullValidator(MessageTemplate = 
          "You must supply your experience in years")]
        [TypeConversionValidator(typeof(int), 
          MessageTemplate = "You must supply a valid 
                             number of experience in years")]
        [RangeValidator("0", RangeBoundaryType.Inclusive, "30", 
          RangeBoundaryType.Inclusive, 
          MessageTemplate = "Your experience in years 
                             must be between {3} and {5}")]
        string ExperienceInYears,
            
        [NotNullValidator(MessageTemplate = "You must supply your currency")]
        [StringLengthValidator(1, RangeBoundaryType.Inclusive, 3, 
          RangeBoundaryType.Inclusive, 
          MessageTemplate = "Currency code must 
                             be between {3} and {5} characters.")]
        string Currency,

        [NotNullValidator(MessageTemplate = 
          "You must supply your certificate status")]
        [TypeConversionValidator(typeof(bool), 
          MessageTemplate = "You must supply a valid 
                             status for your certificate status")]
        string HasCertificate,

        [NotNullValidator(MessageTemplate = 
          "You must supply your status for management involvement")]
        [TypeConversionValidator(typeof(bool), 
          MessageTemplate = "You must supply a valid 
                             status for management involvement")]
        string InvolvedInManagement
    );
}

以上,您可以看到 SalaryService 的契约。 为了使 WCF 服务与验证块一起工作,我们需要做两件事

  1. 使用 ValidationBehavior 属性修饰服务契约(接口)
  2. 使用 [FaultContract(typeof(ValidationFault))] 修饰操作

通过执行这些项目,我们告诉验证块检查验证,并在失败时向客户端提供验证错误。 让我们看看客户端现在如何获得这些错误消息。

客户端

SalaryServiceReference.SalaryServiceClient salaryClient;

private void btnSendDataPartial_Click(object sender, RoutedEventArgs e)
{
    salaryClient = new SalaryServiceReference.SalaryServiceClient();

    try
    {
        var result = salaryClient.CalculatePartial(
                Convert.ToInt32(this.txtEducationLevel.Text),
                Convert.ToInt32(this.txtExperienceInYears.Text),
                this.txtCurrency.Text,
                Convert.ToBoolean(this.txtHasCertificate.Text),
                Convert.ToBoolean(this.txtInvolvedInManagement.Text));

        MessageBox.Show(result);
    }
    catch (FaultException<ValidationFault> validationEx)
    {
        // We check for the error messages
        // and the parameters which cause the failure
        foreach (var validationError in validationEx.Detail.Details)
        {
            MessageBox.Show(String.Format("Invalid input for {0} - {1}", 
                       validationError.Tag, validationError.Message));
        }

        salaryClient.Abort();
    }
    catch (Exception ex)
    {
        MessageBox.Show("Unhandled exception: " + ex.ToString());

        salaryClient.Abort();
    }
    finally
    {
        if (salaryClient.State == CommunicationState.Opened)
        {
            salaryClient.Close();
        }
    }
}

private void btnSendDataFull_Click(object sender, RoutedEventArgs e)
{
    salaryClient = new SalaryServiceReference.SalaryServiceClient();

    try
    {
        // We rely fully on the service, so we send the input as we get from UI
        var result = salaryClient.CalculateFull(
                this.txtEducationLevel.Text,
                this.txtExperienceInYears.Text,
                this.txtCurrency.Text,
                this.txtHasCertificate.Text,
                this.txtInvolvedInManagement.Text);

        MessageBox.Show(result);
    }
    catch (FaultException<ValidationFault> validationEx)
    {
        // We check for the error messages
        // and the parameters which cause the failure
        foreach (var validationError in validationEx.Detail.Details)
        {
            MessageBox.Show(String.Format("Invalid input for {0} - {1}", 
                 validationError.Tag, validationError.Message));
        }

        salaryClient.Abort();
    }
    catch (Exception ex)
    {
        MessageBox.Show("Unhandled exception: " + ex.ToString());

        salaryClient.Abort();
    }
    finally
    {
        if (salaryClient.State == CommunicationState.Opened)
        {
            salaryClient.Close();
        }
    }
}

以上,您可以看到客户端如何使用 WCF 服务操作。 我们像处理其他类型的 WCF 异常一样获取异常,借助 FaultException<>。 请记住,我们使用 ValidationFault 修饰了服务操作,它是验证块提供的自定义 SOAP 异常,因此我们可以使用 FaultException<ValidationFault> 检测验证异常。

捕获验证异常后,很容易遍历错误消息和导致验证异常的参数。 让我们现在看看它的实际效果。

示例

这是来自客户端 WPF 应用程序的屏幕截图

Screen from WPF

在填写输入并单击其中一个按钮后,我们会看到一个类似的屏幕,包括错误消息和 WCF 服务通过验证块提供的理由。

Result returned from WCF service

此外,我们有两种方法,CalculatePartialCalculateFull。 这两种方法之间的区别在于,第一种方法使用强类型参数,而后者使用字符串类型作为所有参数的基本类型,并强制验证块通过属性 TypeConversionValidator 验证输入类型。

最后的寄语

在验证方面,验证块令人印象深刻,并且通过支持 WCF、WPF、WinForms 和 ASP.NET 的特定于技术的功能而保持其强大的功能。 与其他解决方案相比,它使验证更简单且更易于维护,并使您专注于要验证的内容。 我试图解释如何在 Microsoft Enterprise Library 中集成验证块提供的 WCF 功能。 最后,我想提一下在 WCF 实现中使用验证块的方式差异。 在 WCF 中,不支持使用配置文件验证参数,因此我们必须考虑使用基于代码的验证。

© . All rights reserved.