簡體   English   中英

如何在傳遞到控制器C#Web API的模型上創建自定義驗證消息

[英]How do I create a custom validation message on a model passed into a controller c# web api

如何在傳遞給ac#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)
    {
    }
}

如果我將此對象發布到Post操作中:

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

在我的LongValidation的有效方法中,我獲得了long的默認值not:“ 1aaa”,因此無法在驗證器中執行正確的驗證。

這是Long Validator的代碼:

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;
        }
    }
}

1aaa不是long值,而是string值。 因此,當您將數據提交到端點時,默認的模型綁定器將無法將此字符串值映射到您的long? 屬性。

如果您絕對希望將此字符串值映射到clas屬性並得到驗證,則需要將屬性更改為long? string類型。 但是,當然,現在,您需要在代碼的其他部分將其轉換為long!

如果您在正常使用情況下期望數值,我建議您僅使用適當的數值類型。 在您的代碼中,您可以檢查它是否為null並根據需要使用它。

看到這個帖子: 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));
                }
            }
        }
    }
}

基於Kevin的出色回答,我創建了以下類以在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方法是一個簡單的擴展方法,您可以自己編寫。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM