当可以为null的struct时,Action参数对象属性会导致ArgumentNullException

时间:2014-11-24 14:17:42

标签: c# asp.net-mvc-5

当我接受一个对象进入我今天的一个动作时,我发现如果我的对象有一个可以为空的结构的属性,并且我填充了它,我得到了一个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; }
}

现在,如果我调用以下网址: 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。

以下网址可以使用:http://EXAMPLE.COM/Home/Test/?ArbitraryProperty=Foo&SpecialDateA.Year=2014&SpecialDateA.Month=8&SpecialDateA.Day=12

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

修改

为了澄清,在我的请求中反序列化对象时,MVC框架抛出了ArgumentNullException(参见示例URL)。 上面代码中的Test操作放在我的HomeController中,在这个例子中执行永远不会进入方法,在此之前抛出错误(调用示例URL时)。

编辑2: 关于@Shoe的评论,我还测试了以下网址: 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; }
}

1 个答案:

答案 0 :(得分:2)

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

由于您正在使用Nullable<SpecialDate>作为&#34; SpecialDateB&#34;,因此MVC在调用Activator.CreateInstance(System.Type)时会获得空引用,因为它没有初始值。然后,MVC更新触发模型验证的模型状态。

这就是崩溃的原因。

MVC用于验证的System.ComponentModel.DataAnnotations.ValidationContextMSDN reference here)要求&#34;实例&#34;参数(在这种情况下,&#34; SpecialDateB&#34;属性的值)不为空,否则抛出ArgumentNullException

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

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

修改

澄清我的答案:我的意思是声称&#34; MVC不支持参数的Nullable<>类型&#34;仅针对所呈现的案例。像intDateTime等简单类型可以作为可以为空的参数使用。但是,只要您将复杂类型创建为结构并尝试将其用作可为空的参数,MVC就无法处理它。无论您是为其指定值,还是它是可选的。很抱歉我的上述答案不清楚。