• 集成Data Annotations到WCF实现验证


           前面一篇文章,我们介绍了使用Enterprise Libary VAB来实现WCF参数验证。你有可能感觉Enterpise Library 太重量级了,是的,现在我们还要可以借助Data Annotations来实现轻量级解决方案,它曾用于Asp.net MVC等应用程序中,您可能比较熟悉。它们是集成于.net framework。这里我们关键是要实现IParameterInspector接口, 下面是一部分的核心代码:

    public class ValidatingParameterInspector: IParameterInspector
        {
            private readonly IEnumerable<IObjectValidator> _validators;
            private readonly IErrorMessageGenerator _errorMessageGenerator;
     
            public ValidatingParameterInspector(IEnumerable<IObjectValidator> validators, IErrorMessageGenerator errorMessageGenerator)
            {
                ValidateArguments(validators, errorMessageGenerator);
     
                _validators = validators;
                _errorMessageGenerator = errorMessageGenerator;
            }
     
            public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
            {            
            }
     
            public object BeforeCall(string operationName, object[] inputs)
            {
                var validationResults = new List<ValidationResult>();
     
                foreach (var input in inputs)
                {
                    foreach (var validator in _validators)
                    {
                        var results = validator.Validate(input);
                        validationResults.AddRange(results);                    
                    }                                
                }
     
                if (validationResults.Count > 0)
                {
                    throw new FaultException(_errorMessageGenerator.GenerateErrorMessage(operationName, validationResults));
                }
     
                return null;
            }
     
            private static void ValidateArguments(IEnumerable<IObjectValidator> validators, IErrorMessageGenerator errorMessageGenerator)
            {
                if (validators == null)
                {
                    throw new ArgumentNullException("validators");
                }
     
                if (!validators.Any())
                {
                    throw new ArgumentException("At least one validator is required.");
                }
     
                if (errorMessageGenerator == null)
                {
                    throw new ArgumentNullException("errorMessageGenerator");
                }
            }
        }

    在CodePlex上有一个WCF Data Annotations开源项目就是解决这个问题。下面我们来看如何使用:

        [ServiceContract]
        public interface IService1
        {
            [OperationContract]
            string GetData(int value);
     
            [OperationContract]
            CompositeType GetDataUsingDataContract(CompositeType composite);
        }


    Service对应的DataContract,您可以看到我们标记[Required]和[StringLength]验证。

        [DataContract]
        public class CompositeType
        {
            bool boolValue = true;
            string stringValue = string.Empty;
     
            [DataMember]
            [Required]
            public bool BoolValue
            {
                get { return boolValue; }
                set { boolValue = value; }
            }
     
            [DataMember]
            [Required]
            [StringLength(500, MinimumLength = 5)]
            public string StringValue
            {
                get { return stringValue; }
                set { stringValue = value; }
            }
        }


    实现在Service的代码如下:

        //[ValidateDataAnnotationsBehavior]
        public class Service1 : IService1
        {
            public string GetData(int value)
            {
                return string.Format("You entered: {0}", value);
            }
     
            public CompositeType GetDataUsingDataContract(CompositeType composite)
            {
                if (composite == null)
                {
                    throw new ArgumentNullException("composite");
                }
                if (composite.BoolValue)
                {
                    composite.StringValue += "Suffix";
                }
                return composite;
            }
        }


    如果您使用配置文件就不需要标注ValidateDataAnnotationsBehaviorAttribute了:

      <system.serviceModel>
        <extensions>
          <behaviorExtensions>
            <add name="validateDataAnnotationsBehavior"
                 type="DevTrends.WCFDataAnnotations.ValidateDataAnnotationsBehaviorExtensionElement, DevTrends.WCFDataAnnotations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          </behaviorExtensions>
        </extensions>
        <behaviors>
          <serviceBehaviors>
            <behavior>
             <validateDataAnnotationsBehavior/>
              <serviceMetadata httpGetEnabled="True"/>
              <serviceDebug includeExceptionDetailInFaults="False" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>


    我们来写一些基于xunit的单元测试 来验证它们:

        /// <summary>
        /// Wcf unit testing for  http://localhost:17347/WcfService.svc
        /// </summary>
        public class WcfTestingWCFDataAnnotations
        {
            [Fact]
            public void Should_Arise_Validation_Exception_With_ShortString()
            {
                var client = new Service1Client();
                var composetype = new CompositeType
                {
                    BoolValue = true,
                    StringValue = "two"
                };
     
                var exception = Assert.Throws<FaultException>(
        () => { var result = client.GetDataUsingDataContract(composetype); }
    );
                Assert.Equal(
                    @"Service operation GetDataUsingDataContract failed due to validation errors: 
     
    StringValue: The field  must be a string with a minimum length of 5 and a maximum length of 500. 
    ",
                exception.Message);
     
            }
     
            [Fact]
            public void Should_Get_CorrectString()
            {
                var client = new Service1Client();
                var composetype = new CompositeType
                {
                    BoolValue = true,
                    StringValue = "twothree"
                };
                 var result=client.GetDataUsingDataContract(composetype);
                 composetype.StringValue += "Suffix";
                 Assert.Equal(composetype.StringValue, result.StringValue);
            }
        }

    您还可以使DataContract实现IValidatableObject接口 达到验证的效果:
        [DataContract]
        public class CompositeType : IValidatableObject
        {
            bool boolValue = true;
            string stringValue = string.Empty;
     
            [DataMember]
            public bool BoolValue
            {
                get { return boolValue; }
                set { boolValue = value; }
            }
     
            [DataMember]
            public string StringValue
            {
                get { return stringValue; }
                set { stringValue = value; }
            }
     
            public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
            {
                if (StringValue.Length < 5)
                {
                    yield return new ValidationResult("StringValue must be greater than 5", new[] { "StringValue" });
                }
            }
        }


    这是一个简单示例,希望对您WCF开发有帮助。

    您可能感兴趣的文章:

    使用EnterpriseLibrary Validation Block对WCF做验证
    构建WCF的消息代理


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

  • 相关阅读:
    为甚么 国企做互联网总做不起来?
    WEB开发:Java与Php对比
    String中的CompareTo
    String API
    死锁(Deadlock)
    100人100盏灯(详解)
    debian、ubuntu安装metasploit通用方法
    xman随机数相关题目
    CTF辅助脚本
    2019全国大学生信息安全竞赛ciscn-writeup(4web)
  • 原文地址:https://www.cnblogs.com/wintersun/p/2631631.html
Copyright © 2020-2023  润新知