操作参数对象属性在可为空的结构时导致参数空异常

本文关键字:参数 结构 异常 对象 属性 操作 | 更新日期: 2023-09-27 18:31:39

当我今天接受一个对象进入我的一个操作时,我发现如果我的对象有一个可为空的结构的属性并且我填充了它,我得到了一个 ArgumentNullException。

这就是它的样子(极度简化,使用 GET 创建一个更简单的示例):

//Action
[HttpGet]
public JsonResult Test(SuperClass model)
{
    return Json("The will not work...", JsonRequestBehavior.AllowGet);
}
//...
public class SuperClass
{
    public string ArbitraryProperty { get; set; }
    public SpecialDate SpecialDateA { get; set; }
    //This seems to be the problem
    public SpecialDate? SpecialDateB { get; set; }
}
public struct SpecialDate
{
    public int? Year { get; set; }
    public int Month { get; set; }
    public int Day { get; set; }
}

现在,如果我调用以下 URL:http://EXAMPLE.COM/Home/Test/?ArbitraryProperty=Foo&SpecialDateA.Year=2014&SpecialDateA.Month=8&SpecialDateA.Day=12&SpecialDateB.Year=2015&SpecialDateB.Month=9&SpecialDateB.Day=10然后我已经设置了我真正需要的所有数据,但我在System.ComponentModel.DataAnnotations.ValidationContext构造中得到了一个ArgumentNullException。

但是,以下 URL 将起作用:http://EXAMPLE.COM/Home/Test/?ArbitraryProperty=Foo&SpecialDateA.Year=2014&SpecialDateA.Month=8&SpecialDateA.Day=12

因此,在 MVC5 中将可为空的结构属性设置为操作参数不起作用。在这种情况下,我只会切换类的结构,但知道为什么这不起作用会很有趣。

编辑:

澄清一下,在我的请求中反序列化对象时,MVC 框架会抛出 ArgumentNullException(请参阅示例 URL)。在此示例中,上述代码中的测试操作放置在我的 HomeController 中,并且执行永远不会达到输入方法的程度,错误会在此之前引发(调用示例 URL 时)。

编辑2:关于@Shoe的评论,我还测试了以下URL:http://EXAMPLE.COM/Home/Test/?ArbitraryProperty=Foo&SpecialDateA.Year=2014&SpecialDateA.Month=8&SpecialDateA.Day=12&SpecialDateB.Value.Year=2015&SpecialDateB.Value.Month=9&SpecialDateB.Value.Day=10

我所做的是尝试通过其 Value 属性分配 SpecialDateB,但它似乎也不起作用。

编辑3:

为了进一步澄清,这里有一个更简单的问题示例:

这有效:

[HttpGet]
public JsonResult Fest(int? foo)
{
    return Json("This will work", JsonRequestBehavior.AllowGet);
}

这不起作用:

[HttpGet]
public JsonResult Fest(Fee fee)
{
    return Json("This won't work...", JsonRequestBehavior.AllowGet);
}
...
public class Fee
{
    public int? Foo { get; set; }
}

操作参数对象属性在可为空的结构时导致参数空异常

ASP.NET MVC 的默认模型绑定器使用 Activator.CreateInstance(System.Type) 来创建模型及其属性,并且它没有用于处理Nullable<>类型的特殊魔力。

由于你对"SpecialDateB"使用了Nullable<SpecialDate>,MVC 在调用 Activator.CreateInstance(System.Type) 时会得到一个空引用,因为它没有初始值。然后,MVC 更新触发模型验证的模型状态。

这就是崩溃的地方。

MVC 用于验证的System.ComponentModel.DataAnnotations.ValidationContext(此处为 MSDN 参考)要求"实例"参数(在本例中为"SpecialDateB"属性的值)不为 null,否则会引发ArgumentNullException

简而言之,MVC 不支持参数(或参数属性,如您的情况)的Nullable<>类型。

我建议使用类而不是结构,直到 MVC 团队修复了对 Nullable<> 的支持。

编辑:

澄清我的答案:我声称"MVC 不支持参数的Nullable<>类型"的意思仅适用于所介绍的情况。简单的类型,如intDateTime等,作为可为空的参数可以正常工作。但是,一旦将复杂类型创建为结构并尝试将其用作可为 null 的参数,MVC 将无法处理它。无论是否为其指定值,或者它是否可选。很抱歉在我上面的回答中不清楚。