Ajax 传递空值但控制器在 ASP.NET MVC 中为空
Posted
技术标签:
【中文标题】Ajax 传递空值但控制器在 ASP.NET MVC 中为空【英文标题】:Ajax passing empty value but Controller get null in ASP.NET MVC 【发布时间】:2020-05-24 11:56:55 【问题描述】:我正在使用ASP.NET MVC
,但从Ajax
发送到我的控制器的值有问题。
假设我有这样的 SampleViewModel
:
public class SampleViewModel
private string _firstName = string.Empty;
public SampleViewModel()
_firstName = string.Empty;
public string FirstName
get return _firstName;
set _firstName = value ?? string.Empty;
public string LastName get; set;
public string FullName get; set;
控制器
[HttpPost]
public JsonResult ActionSubmit(SampleViewModel model)
var result = "";
if(model.FirstName == null)
result += "\nFirstName is null";
if(model.LastName == null)
result += "\nLastName is null";
return Json(result);
Ajax
$('.submit').click(function()
$.ajax(
url: '@Url.RouteUrl(new action="ActionSubmit", controller="Home")',
data: JSON.stringify( FirstName: '', LastName: '', FullName: 'Phong_Nguyen' ),
// Even though I use FirstName: '', LastName: '', FullName: 'Phong_Nguyen' without JSON.stringify
type: 'POST',
dataType: 'json',
contentType: "application/json; charset=utf-8",
success: function(resp)
alert(resp);
);
);
如您所见,我发送空值,但在控制器端,我得到 null(响应值始终“LastName 为 null”):
问题
为什么当我在 Ajax 中发送 empty
时,我的控制器中得到了 null
值?
有没有更好更优雅的方法来解决我的问题,如下所示?
public string FirstName
get return _firstName;
set _firstName = value ?? string.Empty;
【问题讨论】:
如果您从 Ajax 调用中传递了一些值 - 您的控制器是否获得了这些值? 是的,先生。这是一个很好的问题,我刚刚用更多细节更新了我的问题。请看一下。 试试FirstName: '""'
(单引号内有双引号)。
@史蒂夫格林。不幸的是,它仍然不起作用ibb.co/7gWjjmL
做一件事,在视图上创建对象,除了全名之外,不要在其中放置任何值意味着 objectname.FullName="Phong_Nguyen" 然后传递不要为其余元素放置任何值,您将获得 "" 在你的控制器
【参考方案1】:
为什么当我在 Ajax 中发送空时,我在控制器中得到
null
值?
string
是一个引用类型,它的默认值是null
。如果请求中没有提供值,ModelBinder
会将属性设置为其默认值。
有没有更好更优雅的方法来解决我的问题,如下所示?
您可以使用[DisplayFormat(ConvertEmptyStringToNull = false)]
对属性进行注释,从而保留空字符串值。
您可以编写自定义ModelBinder
,将ConvertEmptyStringToNull
设置为false
,并在全局范围内应用它。
public class NullStringModelBinder : DefaultModelBinder
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
return base.BindModel(controllerContext, bindingContext);
//register it in Application_Start()
ModelBinders.Binders.Add(typeof(string), new NullStringModelBinder());
【讨论】:
感谢您的回复。 2种解决方法看起来不错。但是,如果请求中没有提供任何值,听起来好像真的不适合我的问题。如您所见,我发送的是空值。无论如何+1。 “无价值”是指一个空字符串。ModelBinder
的默认行为是将传入的空字符串转换为null
,因此我们必须显式覆盖该行为。检查第 50 行的 ValueProviderResult
implementation 以了解它如何处理字符串转换。 ValueProviderResult
负责将输入转换为Action的参数类型,如果修剪后的输入字符串长度为0
,则将目标设置为null
。
你能告诉我.Net为什么会有这样的变化吗?我的意思是我们都知道我们应该有一个空值来避免NullReferenceException
而不是null,对吧?
@Phong 显然modelBuinder默认使用string.IsNullOrEmpty
来检查字符串值
@Phong 根据this,决定与WebForms 将空字符串视为null
的行为保持一致。而且我认为另一个原因是也与引用类型的期望保持一致——正如我在原来的帖子中所说的那样——例如默认情况下,空数组的输入也被转换为null
,因为它也是一个引用类型,因为将一些引用类型初始化为非空值而将其他引用类型转换为null
是没有意义的,而是它们都应该具有相同的统一行为。【参考方案2】:
此特定更改已记录在 here 中,它是 MVC 1.0
的重大更改之一。这种将空字符串绑定到null
s 的逻辑由DefaultModelBinder
使用的ModelMetadata.ConvertEmptyStringToNull
属性控制。
现在,如果您不想注释所有属性,可以创建自定义模型绑定器:
public class EmptyStringModelBinder : DefaultModelBinder
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
Binders = new ModelBinderDictionary() DefaultBinder = this ;
return base.BindModel(controllerContext, bindingContext);
并将其设置在您的Global.asax
:
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
或者在你的具体行动中:
[HttpPost]
public JsonResult ActionSubmit([ModelBinder(typeof(EmptyStringModelBinder))SampleViewModel model)
为什么要这样做?
这样做是因为string
的默认值为null
,并且因为string
是reference type
,并且所有引用类型的默认值为null
。因此,框架的这种变化可能是合理的。但另一方面,我们应该尽量避免空值,因此我们需要编写自定义模型绑定器来避免这种情况。
有一个关于为什么default value of the string type null instead of an empty string? 的问题。您可以仔细阅读以了解更多关于为什么进行此更改的信息。
根据@Anton:在c# 8.0
中,您可以打开空检查以避免NullReferenceException
并设置为引用类型默认值而不是null
【讨论】:
你能告诉我.Net为什么会有这样的变化吗?我的意思是我们都知道我们应该有一个空值来避免NullReferenceException
而不是null,对吧?
@Phong 这样做是因为string
的默认值为null
,并且因为string
是reference type
,并且所有引用类型的默认值为null
。因此,框架的这种变化可能是合理的。但另一方面,我们应该尽量避免空值,因此我们需要编写一个自定义模型绑定器来避免这种情况。你可以看看这个问题:***.com/questions/14337551/…
@Phong 这是 C# 设计的。现在在 c# 8.0 中,您可以打开 null cheks 以避免 NullReferenceException
并设置为引用类型默认值而不是 ``null
是的,我知道我们需要完全避免空值。那么为什么.Net会自动从空转换为null,那么现在我们又要转换一个,不知道为什么我们得到了上面帖子那样的奇怪值。
@Phong .Net 自动将空转换为空,因为当遇到空的 string
时,它会设置 string
的默认值,并且由于 string
是 reference type
并且所有引用类型的默认值为null
,它会将它们更改为null,这是框架的预期行为。【参考方案3】:
当你在 C# 中声明一个字符串变量时,它的值是null
,直到被赋值。
当通过表单提交发送数据时,任何未输入信息的字段都将作为空字符串发送。 没有提供任何信息的最佳模拟是null
,因此它将这些值设置为null
(或者更可能的是,根本不设置值)。
MVC 无法区分空字符串(因为没有提供信息)和空字符串(因为这是在传输之前在 javascript 中分配的值)。它只知道其中一个字段没有信息,因此该值应该是null
。
【讨论】:
感谢您的回答。不幸的是,我找不到比上述答案更有用的新信息。因此,您可以清楚地在解决方案中添加更多信息。【参考方案4】:我决定从@Rahul Sharma's 和@rhytonix's 中总结答案,并为您提供示例和更详细的解释。
为什么当我在 Ajax 中发送空时,我的控制器中得到空值?
这仅仅是因为MVC 2.0
默认将字符串初始化为空。更准确地说,如果empty
字符串表示没有值,那么.NET 会设置它的默认值。并且默认字符串(属于引用类型)是null
。
更多详情Model String Property Binding Breaking Change
有没有更好的方法和更优雅的方法来解决我的问题,如下所示?
有一些方法可以将字符串属性绑定为string.Empty
而不是null
1.从 C# 6 开始,您可以使用 DefaultValueAttribute 将自动属性设置为如下所示的初始值
public string LastName => string.Empty;
基本上,这种方式与帖子中提到的OP的解决方案相同,只是更优雅。
2。通过从DefaultModelBinder
继承并将内部ModelMetaData
对象上的ConvertEmptyStringToNull
值更改为false 来自定义IModelBinder
的默认实现。
public sealed class EmptyStringModelBinder : DefaultModelBinder
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
return base.BindModel(controllerContext, bindingContext);
然后在Global.asax.cs
的Application_Start()
方法中你需要像下面这样完成
protected void Application_Start()
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
RegisterRoutes( RouteTable.Routes );
3.像下面这样使用DisplayFormatAttribute.ConvertEmptyStringToNull Property
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string LastName get; set;
只是因为在ModelMetadata
true
如果空字符串值自动转换为null
; 否则,false
。 默认为true
【讨论】:
以上是关于Ajax 传递空值但控制器在 ASP.NET MVC 中为空的主要内容,如果未能解决你的问题,请参考以下文章
通过 Ajax 将布尔值传递给 asp.net api 控制器
将多个参数从 ajax post 传递到 asp.net mvc 控制器
使用 Jquery Ajax 将数组传递给 asp.net C# 控制器