• 使用EnterpriseLibrary Validation Block对WCF做验证


           EnterpriseLibrary Validation Application Block 5.0  用来对Application做验证是常见的应用。下面我们来实现在Windows Communication Foundation (WCF 4 )中验证集成。引用Microsoft.Practices.EnterpriseLibrary.Validation.dll 与 Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.dll,定义Contract的类如下:

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


    上面的代码,做了非空验证,范围验证,长度等验证。使用[FaultContract(typeof(ValidationFault))], 让我们能够检测到 验证的异常。
    接着是它的实现:

        public class SalaryService : ISalaryService
        {
            private string Calculate(int EducationLevel, int ExperienceInYears, string Currency, bool HasCertificate, bool InvolvedInManagement)
            {
                // Make our calculations with the input given by the clients
                int estimatedSalary = EducationLevel * 100 + ExperienceInYears * 10 + (HasCertificate ? 50 : 0) + (InvolvedInManagement ? 100 : 0);
     
                return String.Format("Your estimated salary is {1}{0}", Currency, estimatedSalary);
            }
     
            public string CalculatePartial(int EducationLevel, int ExperienceInYears, string Currency, bool HasCertificate, bool InvolvedInManagement)
            {
                return Calculate(EducationLevel,
                            ExperienceInYears,
                            Currency,
                            HasCertificate,
                            InvolvedInManagement);
            }
     
            public string CalculateFull(string EducationLevel, string ExperienceInYears, string Currency, string HasCertificate, string InvolvedInManagement)
            {
                return Calculate(Convert.ToInt32(EducationLevel),
                            Convert.ToInt32(ExperienceInYears),
                            Currency,
                            Convert.ToBoolean(HasCertificate),
                            Convert.ToBoolean(InvolvedInManagement));
            }
        }


    在配置文件中:

        <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>
            <behaviors>
                <serviceBehaviors>
                    <behavior>
                        <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                        <serviceMetadata httpGetEnabled="true"/>
                        <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
                        <serviceDebug includeExceptionDetailInFaults="true"/>
                    </behavior>
                </serviceBehaviors>
            </behaviors>
            <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
        </system.serviceModel>


    下面我们可以来调用它了,看客户端,通过引用生成的代理。这里我们使用WPF来演示:

    前端XAML:

    <Window x:Class="ServiceTestClient.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="450">
        <Window.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Margin" Value="5"></Setter>
                <Setter Property="HorizontalAlignment" Value="Left"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
            <Style TargetType="{x:Type TextBox}">
                <Setter Property="Margin" Value="5"></Setter>
                <Setter Property="HorizontalAlignment" Value="Left"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Margin" Value="5"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="VerticalAlignment" Value="Top"></Setter>
                <Setter Property="Width" Value="250"></Setter>
            </Style>
        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="220" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <TextBlock Name="textBlock1" Grid.Row="0" Grid.Column="0" Text="Education Level (2-5)" />
            <TextBlock Name="textBlock2" Grid.Row="1" Grid.Column="0" Text="Experience (Years)" />
            <TextBlock Name="textBlock3" Grid.Row="2" Grid.Column="0" Text="Currency" />
            <TextBlock Name="textBlock4" Grid.Row="3" Grid.Column="0" Text="Valid Certificate (True/False)"  />
            <TextBlock Name="textBlock5" Grid.Row="4" Grid.Column="0" Text="Management Experience (True/False)"/>
            <TextBox Name="txtEducationLevel" Width="120" Grid.Row="0" Grid.Column="1" />
            <TextBox Name="txtExperienceInYears" Width="120" Grid.Row="1" Grid.Column="1" />
            <TextBox Name="txtCurrency" Width="120" Grid.Row="2" Grid.Column="1" />
            <TextBox Name="txtHasCertificate" Width="120" Grid.Row="3" Grid.Column="1" />
            <TextBox Name="txtInvolvedInManagement" Width="120" Grid.Row="4" Grid.Column="1" />
            <StackPanel Grid.ColumnSpan="2" Grid.Row="5" Orientation="Vertical">
                <Button Name="btnSendDataPartial" Content="Calculate salary using partial validation" Click="btnSendDataPartial_Click"></Button>
                <Button Name="btnSendDataFull" Content="Calculate salary using full validation" Click="btnSendDataFull_Click"></Button>
            </StackPanel>
        </Grid>
    </Window>


    窗体后面的代码是这样的:

        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
     
            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();
                    }
                }
            }
        }


    在程序中Catch验证的异常,让他们一个个显示出来,当然在实际项目中,我们需要做更多的事儿,例如日志,或具体的异常处理机制。
    最后看一下Client端的配置文件:

        <system.serviceModel>
            <bindings>
                <basicHttpBinding>
                    <binding name="BasicHttpBinding_ISalaryService" 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:2262/SalaryService.svc" binding="basicHttpBinding"
                    bindingConfiguration="BasicHttpBinding_ISalaryService" contract="SalaryServiceReference.ISalaryService"
                    name="BasicHttpBinding_ISalaryService" />
            </client>
        </system.serviceModel>


    好了,上面的程序通过一个简单的逻辑演示WCF中使用Entlib Validation Block做验证。 所有代码在VS2010, .NET 4.0 下通过。

    希望对您开发有帮助。 你可以感兴趣的Posts:

    构建WCF的消息代理



    作者:Petter Liu
    出处:http://www.cnblogs.com/wintersun/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    该文章也同时发布在我的独立博客中-Petter Liu Blog

  • 相关阅读:
    q和blockquote标签的区别
    Python基础数据类型2
    Python基础类型(1)
    Python运算符与编码
    python基础(初识)
    变量,解释器,垃圾回收机制,小整数池总结
    面向对象 --类
    (绑定方法和非绑定方法)类方法,实例方法,静态方法 类属性和实例属性
    logging 模块
    subprocess(cmd命令)模块 && configerparser模块(配置ini文件)
  • 原文地址:https://www.cnblogs.com/wintersun/p/2626794.html
Copyright © 2020-2023  润新知