2017-01-27 8 views
1

c#web APIのコントローラアクションメソッドに渡されたモデルでカスタム検証メッセージを作成するにはどうすればよいですか?ここでコントローラに渡されたモデルでカスタム検証メッセージを作成するにはどうすればいいですか?c#web api

は、モデルである:ここでは

[DataContract] 
public class TestDto //: IValidatableObject 
{ 
    [DataMember] 
    [LongValidation("Its not a long!")] 
    public long? ID { get; set; } 
    [DataMember] 
    public string Description { get; set; } 

    public string DescriptionHidden { get; set; } 
} 

は私のコントローラクラスである:

public class ValuesController : ApiController 
{ 
    // GET api/values 
    public IEnumerable<string> Get() 
    { 
     return new string[] { "value1", "value2" }; 
    } 

    // GET api/values/5 
    public string Get(int id) 
    { 
     return "value"; 
    } 

    // POST api/values 
    public string Post([FromBody]TestDto testDto) 
    { 
     //todo: should a post return any data? 
     if (ModelState.IsValid) 
      return "success!"; 
     else 
     { 
      var ret = string.Empty; 
      foreach (var modelState in ModelState) 
      { 
       ModelErrorCollection errorCollection = modelState.Value.Errors; 
       var errors = string.Empty; 
       foreach (var error in errorCollection) 
       { 
        errors = errors + "exception message: " + error.Exception.Message + ", errorMessage: " + error.ErrorMessage; 
       } 
       ret = ret + "Error: " + modelState.Key + ", " + modelState.Value.Value + ", errors: " + errors; 
      } 
      return ret; 
     } 
    } 

    // PUT api/values/5 
    public void Put(int id, [FromBody]string value) 
    { 
    } 

    // DELETE api/values/5 
    public void Delete(int id) 
    { 
    } 
} 

私はポストの行動にこのオブジェクトを投稿する場合:私のLongValidationの有効で

{ 
"ID" : "1aaa","Description": "sample string 2", 
} 

メソッドでは、私は長いうちのデフォルト値を取得しない: "1aaa"、私はvalidaで正しい検証を実行することはできませんトルーマンここで

はロング検証のためのコードです:

public class LongValidationAttribute : ValidationAttribute 
{ 
    public LongValidationAttribute(string errorMessage) : base(errorMessage) 
    { 
    } 

    public override string FormatErrorMessage(string name) 
    { 
     return base.FormatErrorMessage(name); 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     long ret; 
     bool success = long.TryParse(value.ToString(), out ret); 
     //return base.IsValid(value, validationContext); 
     if (success == false) 
      return new ValidationResult(this.ErrorMessage); 
     else 
     { 
      return ValidationResult.Success; 
     } 
    } 
} 

答えて

1

1aaalong値が、string値ではありません。したがって、データをエンドポイントに送信すると、デフォルトのモデルバインダーはこの文字列値をlong?プロパティにマップすることができません。

この文字列値をclasプロパティにマップして検証する必要がある場合は、プロパティをlong?からstringに変更する必要があります。しかし今はもちろん、コードの他の部分で長い間変換する必要があります。

通常の使用例で数値が必要な場合は、適切な数値型を使用することをお勧めします。あなたのコードでは、それがnullかどうかをチェックし、必要に応じてそれを使用することができます。

1

この記事を参照してください:https://blog.markvincze.com/how-to-validate-action-parameters-with-dataannotation-attributes/

基本的には、カスタムフィルタ属性でMVCパイプラインにフックする必要があります:ケビンの優れた回答に基づいて

public class ValidateActionParametersAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext context) 
    { 
     var descriptor = context.ActionDescriptor as ControllerActionDescriptor; 

     if (descriptor != null) 
     { 
      var parameters = descriptor.MethodInfo.GetParameters(); 

      foreach (var parameter in parameters) 
      { 
       var argument = context.ActionArguments[parameter.Name]; 

       EvaluateValidationAttributes(parameter, argument, context.ModelState); 
      } 
     } 

     base.OnActionExecuting(context); 
    } 

    private void EvaluateValidationAttributes(ParameterInfo parameter, object argument, ModelStateDictionary modelState) 
    { 
     var validationAttributes = parameter.CustomAttributes; 

     foreach (var attributeData in validationAttributes) 
     { 
      var attributeInstance = CustomAttributeExtensions.GetCustomAttribute(parameter, attributeData.AttributeType); 

      var validationAttribute = attributeInstance as ValidationAttribute; 

      if (validationAttribute != null) 
      { 
       var isValid = validationAttribute.IsValid(argument); 
       if (!isValid) 
       { 
        modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name)); 
       } 
      } 
     } 
    } 
} 
+0

ありがとうございました。指定されたコンテキストで適切な方法でshow-casingを実行していただきありがとうございます。指定されたコードスニペットはasp.netコアで動作します。私は以下の答えでコードをリファクタリングして、人々がmvc4 +で同じ機能を達成するのに苦労するのを助けました。再度、感謝します。 – xDisruptor

0

私は希望を達成するために以下のクラスを作成しましたMVC4/MVC5下の効果:

public sealed class ValidateActionParametersAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext context) 
    { 
     var descriptor = context.ActionDescriptor; 
     if (descriptor != null) 
     { 
      var modelState = context.Controller.ViewData.ModelState; 
      foreach (var parameterDescriptor in descriptor.GetParameters()) 
      { 
       EvaluateValidationAttributes(
        suppliedValue: context.ActionParameters[parameterDescriptor.ParameterName], 
        modelState: modelState, 
        parameterDescriptor: parameterDescriptor 
       ); 
      } 
     } 

     base.OnActionExecuting(context); 
    } 

    static private void EvaluateValidationAttributes(ParameterDescriptor parameterDescriptor, object suppliedValue, ModelStateDictionary modelState) 
    { 
     var parameterName = parameterDescriptor.ParameterName; 
     parameterDescriptor 
      .GetCustomAttributes(inherit: true) 
      .OfType<ValidationAttribute>() 
      .Where(x => !x.IsValid(suppliedValue)) 
      .ForEach(x => modelState.AddModelError(parameterName, x.FormatErrorMessage(parameterName))); 
    } 
} 

注:上記の使用.ForEach方法は、あなたがWRIできる単純な拡張メソッドでありますあなた自身で。

関連する問題