将 null 赋给可空 int 时发生错误 - "值 'null' 对该属性无效"

21

我有一个在我的视图模型中的属性:

[DisplayName("Region")]
public int? RegionId { get; set; }

我将我的视图模型传递给控制器,但是当RegionId为空时,它在ModelState.IsValid 处失败。如果我传递一个整数,它就可以正常工作。

错误信息如下:

值“null”对于Region无效

我也尝试在检查ModelState.IsValid之前调用此代码,但是我收到同样的错误:

if (viewModel.RegionId == null)
    viewModel.RegionId = (int?)null;

这里的问题是什么?为什么我不能将null赋给可为空的东西?


如果 (viewModel.RegionId == null),那么为什么要将其赋值为 null?viewModel.RegionId已经是null了吗? - Bala R
@Bala - 我看了其他关于同样问题的帖子,他们说应该赋值(int?)null而不是null - Steven
@Steven Bala提出了一个很好的观点。如果RegionID已经为空,那么就没有什么工作要做了,只需省略第二行,因为即使它起作用,也不会有任何效果。 - JohnFx
6个回答

14

这里是另一个可能的解释。

我正在使用jQuery进行AJAX POST请求到一个MVC action方法,代码如下:

$.post('url/here',dataObject);

jQuery会将数据对象转换为查询字符串。我使用默认的模型绑定器将值推送到我的ViewModel中。模型验证失败,提示"The value 'null' is not valid for field name"。但是该属性为可空int类型。在检查原始POST数据后,我发现我正在POST的数据对象被序列化为以下查询字符串:

Field1=null&Field2=value&Field3=value

而不是这个:

Field1=&Field2=value&Field3=value

因此,模型验证理所当然地抱怨将字符串文字“null”分配给可空int。 一个解决方案是在POST之前检查NULL。 我希望我有时间深入挖掘,但我刚刚转而发送数据对象的JSON表示形式,它正确处理了null值。


1
这在我的情况下也是同样的原因,并且是由于 HTML 的 <select> 元素缺少 <option> 元素引起的!我添加了单个 <option></option> 元素,问题得以解决。事实上,HTML 规范规定 <select> 元素必须至少有一个 <option> 元素:w3.org - HTML 文档中的表单 - mco
干得好先生!那正是我的问题。我正在将一些属性初始化为JSON对象的form.Prop = null。现在将其更改为form.Prop ='',一切都恢复正常了。 - Robert MacGrogan
你节省了我好几个小时的时间。谢谢你。 - Pluc

8
在你的Global.asax.cs文件中的Application_Start方法中,添加以下行:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

问题在于,即使对于可空值类型,默认情况下,缺省的验证器提供程序也会添加一个“必需”属性。

你有其他正在使用的ModelValidatorProviders吗?在Global.asax.cs中,在上面显示的那行代码之前添加以下两行代码: ModelValidatorProviders.Providers.Clear(); ModelValidatorProviders.Providers.Add(new DataAnnotationsModelMetadataValidatorProvider()); - counsellorben
这是MVC中的一个bug吗?从文档中可以看到,“获取或设置一个值,该值指示是否需要非空值类型”,这似乎意味着它不应该应用于非空类型。http://msdn.microsoft.com/en-us/library/system.web.mvc.dataannotationsmodelvalidatorprovider.addimplicitrequiredattributeforvaluetypes.aspx - Chris Jackson
我认为你误读了文档。这个属性适用于所有值类型,无论可空或不可空。 - counsellorben
2
文档清楚地说明:“获取或设置一个值,该值指示是否需要非空值类型。”我在ASP.NET MVC3源代码中查找并确认了此内容。当此设置为“true”时,隐式“RequiredAttribute”才会被添加,元数据表明属性“IsRequired”,但尚未有RequiredAttribute。默认情况下,“ModelMetadata”表示对于引用类型和可空类型,模型不是必需的。我也遇到了同样的问题,你提出的解决方案对我也没有起作用。当我找出原因和如何修复它时,我会发布解决方案。 - mco
-1;这不起作用。也许是“我的”项目中的其他问题(也许fluent验证还在干扰它)。但是“我的”项目已经做到了这一点,并且不需要 Required 属性,就要求 null-able 字段。 - James Haug

8

1

我认为问题不在于赋值 null,而是消费代码不接受 null 值。赋值是完全有效的(尽管您的 null 检查是反向的,强制转换是多余的)。

viewModel.RegionId = null;

另外,您可以使用HasValue在可空类型上检查null。虽然实际上这与null检查没有什么不同,但看起来更加简洁:

if (viewModel.RegionId.HasValue)
{
    // do something
}

从技术上讲,在这两个示例中,条件语句都是多余的。 - JohnFx
不,它会将值设置为 null,如果当前不是 null。 - TheCodeKing
好的。那么为什么不在检查它之前将其设置为null呢?结果是相同的。 - JohnFx
我明白你的意思,这个想法是展示问题中HasValue的使用,这里没有真正的上下文。 - TheCodeKing

1

我遇到了一个问题。

我的问题是,我在POST请求中明确将有问题的属性设置为null。因此,类似于您的情况,请求看起来应该是这样的:

RegionId = null

在我的情况下,这很简单,只需省略显式声明(例如,不要说它是null,只需不发送任何数据)。

0
我有一种感觉,问题可能出在你展示的示例代码之外。我创建了一个简单的应用程序,只创建了一个表单并具有可空字段,但它按预期工作。我建议你开始排除设置中的其他变量,直到你能够使用具有可空属性的工作ViewModel,并且你应该能够确定是什么导致了问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接