如果提交了如下所示的表单,并且表单上的
MyField
留空,则默认情况下 Asp.Net Core 模型绑定会将 null 放入模型上的相应属性中,如下所示。
表格示例
<form asp-controller="SomeController" asp-action="SomeAction">
<label asp-for="MyField">My Field</label><input asp-for="MyField" type="text" />
<button type="submit">Submit</button>
</form>
模型示例
public class MyModel{
public string MyField { get; set; }
}
操作方法示例
[HttpPost]
public IActionResult Post(MyModel m) {
//m.MyField will be null if the field was left empty
//but I want it set to a blank string by the model binder
}
但是,由于
MyField
实际上是在 Http Post 主体中传输的,因此我更希望模型绑定器将模型上的 MyField
属性设置为空白字符串,而不是将其设置为 null。对于 Http Post 正文中未传输 MyField
的情况,我更愿意保留 null。如何更改模型绑定器以表现出这种行为?
在
https://github.com/aspnet/Mvc/blob/rel/1.1.3/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Binders/SimpleTypeModelBinder 学习
SimpleTypeModelBinder
的 ASP.NET Core 代码。 cs 我可以看到有一个 ModelMetadata.ConvertEmptyStringToNull
设置默认设置为 true,导致数据绑定时空白字符串转换为 null。但该属性是只读的,所以一开始我不知道如何更改它的值。
@rsheptolut在此页面上的帖子https://github.com/aspnet/Mvc/issues/4988引导我找到了解决方案。
解决方案:
该值必须在启动时设置。这可以通过此类来完成:
public class CustomMetadataProvider : IMetadataDetailsProvider, IDisplayMetadataProvider {
public void CreateDisplayMetadata(DisplayMetadataProviderContext context) {
if (context.Key.MetadataKind == ModelMetadataKind.Property) {
context.DisplayMetadata.ConvertEmptyStringToNull = false;
}
}
}
当它像这样挂接到startup.cs文件的
ConfigureServices
方法中的MvcOptions时
services.AddMvc()
.AddMvcOptions(options => options.ModelMetadataDetailsProviders.Add(new CustomMetadataProvider ()));
现在,在站点范围内,回发的空白字段的默认设置是数据绑定器将相应的模型属性设置为空白字符串而不是 null。是啊!
您是否尝试过让属性具有空字符串的默认值?
public string MyField { get; set; } = string.Empty;
尝试的一个更丑陋的解决方案是:
private string myField = string.Empty;
public string MyField
{
get { return myField ?? string.Empty; }
set { myField = value; }
}
我觉得应该有用
如果您想在 aciton 方法中的
参数级别覆盖
ConvertEmptyStringToNull
行为,您可以这样做(适用于 .NET 5、.NET 6,可能也适用于更高版本):
第 1 步 - 添加此类:
[AttributeUsage(AttributeTargets.Parameter)]
public class AllowEmptyAttribute : DisplayFormatAttribute
{
public AllowEmptyAttribute() : base() { ConvertEmptyStringToNull = false; }
}
第 2 步 - 在控制器中使用
//in your controller
public IActionResult DoStuff(int id, [AllowEmpty] string name)
这是改变它的黑客方法,但它有效。