干净的方式避免“;不可为null类型的参数id的null条目“;输入参数错误

本文关键字:null 参数 类型 id 条目 错误 输入 方式避 | 更新日期: 2023-09-27 17:59:47

在ASP.NET MVC中,我非常喜欢它自动尝试从请求值填充Action的参数的功能。

它让很多东西看起来非常干净,我的表单层次模型可以轻松地通过电线来回移动。

不过它有一个烦人的问题。缺少不可为null的参数的自动异常。这并不是说这个框架是错误的。我理解这背后的原因,但是:

  1. 在相当多的情况下,我有一个单独的int参数作为输入,其中请求一个特定的对象(例如产品的详细信息页面)
  2. 该参数是一个GET参数,因此它在url中可见,并且很容易更改
  3. 如果用户更改了url中的参数,则Web服务器会以错误页面进行响应,并记录错误等

这种错误应该在应用程序中得到很好的处理,我不需要用错误污染我的日志,而且对于这些情况,404错误将更适合IMHO,因为如果没有标识符参数"找不到资源"。

关于如何避免这种情况,我有一些想法,但我希望有一些透明的东西可以在一个地方处理这种情况。

到目前为止,我所做的事情是使参数int?

不是真正透明的,我需要到处检查ID.HasValue,并显式抛出404。这会污染Action逻辑。

解决这个问题的最佳地点是什么?

编辑:

我还想指出的是,尽管抛出HttpException(404,"")仍然是一个例外,但由于浏览器搜索收藏夹等,爬网程序无论如何都会对坏URL发出大量请求,因此我所有的日志记录、警报等都会进行相应的配置。

干净的方式避免“;不可为null类型的参数id的null条目“;输入参数错误

我认为这里合适的挂钩是ModelBinder。

当你想退货404时,你必须想出策略。基于您上面的详细信息,为了简单起见,我将假设任何时候一个名为"id"的参数为null或未按预期传递时,都会生成404。以下是ModelBinder代码示例。

using System.Net;
using System.Web;
using System.Web.Mvc;
public class MyModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var result = base.BindModel(controllerContext, bindingContext);
        if (result == null && bindingContext.ModelName.ToLower() == "id")
        {
            throw new HttpException((int)HttpStatusCode.NotFound, null);
        }
        return result;
    }
}

你把它连接到Global.asax:

protected void Application_Start()
{
    ModelBinders.Binders.DefaultBinder = new MyModelBinder();
}

为了获得更细粒度,您可以只向想要此行为的参数添加一个属性,并使用反射来检查该属性,并且只抛出404异常。在这种情况下,这将导致性能损失。因此,您可以根据需要仅为具有此行为的模型连接特定的ModelBinder。或者,您也可以维护一个Controllers/Actions/Parameters字典来应用行为。

编辑:您还注意到,您特别关注GET请求。该值在模型绑定器中可用:controllerContext.RequestContext.HttpContext.Request.HttpMethod.