統合Data AnnotationsからWCFへの検証

19793 ワード

前編文章では,WCFパラメータ検証を実現するためにEnterprise Libary VABを用いることを紹介した.Enterpise Libraryは重量級すぎると感じるかもしれません.はい、今はData Annotationsを借りて軽量級のソリューションを実現することができます.Aspに使用されています.NetMVCなどのアプリケーションでは、おなじみかもしれません.これらは統合されています.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");
            }
        }
    }



.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
 
CodePlexには、この問題を解決するためのWCF Data Annotationsオープンソースプロジェクトがあります.次に、使用方法について説明します.
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
 
        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);
    }

サービス対応の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; }
        }
    }



.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
サービスに実装されるコードは次のとおりです.
    //[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を構築するMessage Agent
作者:Petter Liu出典:http://www.cnblogs.com/wintersun/本文の著作権は作者とブログ園に共有され、転載を歓迎するが、著者の同意を得ずにこの声明を保留し、文章のページの明らかな位置で原文の接続を与えなければならない.そうしないと、法律責任を追及する権利を保留する.この記事は、私の独立したブログにも掲載されています.Petter Liu Blog.