【问题标题】:Web API Model setter exception not being passed throughWeb API 模型设置器异常未通过
【发布时间】:2016-09-08 23:36:18
【问题描述】:

我有一个 APIController 和一个输入类。

POST 处理程序:

    public void Post([FromBody]NRCSSoilInput input)
    {
            new NRCSSoilWebService().SendRequest(input.box.west, input.box.north, input.box.east, input.box.south);
    }

输入类:

    public class NRCSSoilInput
    {
        public class BBox
        {
            public double north { get; set; }
            public double south { get; set; }
            public double east { get; set; }
            public double west { get; set; }
        }

        private BBox _box;
        public BBox box
        {
            get { return _box; }
            set { Validate(value); _box = value; }
        }

        public void Validate(BBox value)
        {
            if (value.west > value.east)
                throw new ArgumentOutOfRangeException("west", value.west, "West cannot be bigger than east coordinate.");

            ... etc ...
        }
    }

所以发生的情况是,当遇到异常时,不会创建对象(如预期的那样),但代码会继续并在 Post 中点击 SendRequest,然后在 input.box.west 处失败,因为 input.box 为空。这就是 Post 调用返回到前端的内容。我希望它返回的是 ArgumentOutOfRangeException,虽然我会停止代码。

ExceptionMessage:"Object reference not set to an instance of an object."
ExceptionType:"System.NullReferenceException"
Message:"An error has occurred."

我想一个简单的解决方案是将验证移到 Post 中,我不喜欢这个想法,尽管在我看来验证应该在创建 Input 对象时进行。

有几个附带问题:

  • 将验证放入 Post 的另一个优点是我可以将其放入 try catch 块中,然后返回带有 { status: error, message : "error message" } 的 OK 响应,而不是 500回复。

  • 输入 json 必须将东、西等作为整数,但它应该真正接受它们作为字符串,然后也将它们转换。

上面有什么巧妙的方法吗?

【问题讨论】:

  • 你检查我的答案了吗?我错过了什么

标签: c# asp.net-web-api exception-handling


【解决方案1】:

最好的方法是使用 Data Annotations(开箱即用或 FluentValidations)和 Filter 属性,见下文。

第 1 步 - 构建自定义属性。 (我在这个例子中使用了开箱即用的数据注释)

[AttributeUsage(AttributeTargets.Property)]
public class DoubleGreaterThanAttribute : ValidationAttribute
{
    public DoubleGreaterThanAttribute(string doubleToCompareToFieldName)
    {
        DoubleToCompareToFieldName = doubleToCompareToFieldName;
    }

    private string DoubleToCompareToFieldName { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        double west = (double)value;

        double east = (double)validationContext.ObjectType.GetProperty(DoubleToCompareToFieldName).GetValue(validationContext.ObjectInstance, null);

        if (east > west)
        {
            return ValidationResult.Success;
        }
        else
        {
            return new ValidationResult("West cannot be bigger than east coordinate.");
        }
    }
}

步骤 -2 使用自定义属性注释属性

public class NRCSSoilInput
{
    public class BBox
    {
        public double north { get; set; }
        public double south { get; set; }
        [Required]
        public double east { get; set; }
        [Required]
        [DoubleGreaterThan("east")]
        public double west { get; set; }
    }
    public BBox box { get; set; }
}

第 3 步- 添加如下过滤器属性类(最好在 Filters 文件夹中)

[AttributeUsage(AttributeTargets.Method, Inherited = true)]
public class ValidateModelAttribute : ActionFilterAttribute
{
    private readonly Func<Dictionary<string, object>, bool> _validate;

    public ValidateModelAttribute()
        : this(arguments =>
            arguments.ContainsValue(null))
    { }

    public ValidateModelAttribute(Func<Dictionary<string, object>, bool> checkCondition)
    {
        _validate = checkCondition;
    }

    public override void OnActionExecuting(HttpActionContext actionContext)
    {

        var modelState = actionContext.ModelState;

        if (!modelState.IsValid)
            actionContext.Response = actionContext.Request
                 .CreateErrorResponse(HttpStatusCode.BadRequest, modelState);

          }
}

第 4 步 - 在您的控制器上注释过滤器属性

    [HttpPost]
    [ValidateModel]        
    public Void Post(NRCSSoilInput model)
    {
            return Ok();
    }

这样,只有当模型通过所有验证时,您的方法才会被命中。希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-02
    • 2015-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    相关资源
    最近更新 更多