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

posted on 2012-08-07 15:29  PetterLiu  阅读(1346)  评论(0编辑  收藏  举报