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