操作参数对象属性在可为空的结构时导致参数空异常
本文关键字:参数 结构 异常 对象 属性 操作 | 更新日期: 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<>
类型"的意思仅适用于所介绍的情况。简单的类型,如int
、DateTime
等,作为可为空的参数可以正常工作。但是,一旦将复杂类型创建为结构并尝试将其用作可为 null 的参数,MVC 将无法处理它。无论是否为其指定值,或者它是否可选。很抱歉在我上面的回答中不清楚。