.NET 7 Razor Pages荷兰文化下Decimal/DateTime绑定模型为Null问题
问题原因及解决办法
原因分析
当使用AJAX提交数据时,.NET Razor Pages的模型绑定行为和Form提交存在差异:
- Form提交时,模型绑定会自动采用当前请求配置的
nl-NL区域性,能正常解析荷兰格式的Decimal(如2,01)和DateTime(如30-12-2022)。 - AJAX提交JSON数据时,默认模型绑定会使用**不变区域性(InvariantCulture)**解析,该区域性不识别逗号作为小数分隔符、
dd-MM-yyyy的日期格式,导致这两个字段解析失败,触发模型验证错误,最终整个UpdateModel实例为null。
解决办法
方法1:配置后端模型绑定使用请求区域性
在Program.cs中配置MVC模型绑定规则,强制使用当前请求的区域性解析数据:
builder.Services.AddRazorPages() .AddMvcOptions(options => { // 注册自定义模型绑定器,优先处理Decimal和DateTime options.ModelBinderProviders.Insert(0, new DecimalModelBinderProvider()); options.ModelBinderProviders.Insert(1, new DateTimeModelBinderProvider()); }) .AddViewLocalization() .AddDataAnnotationsLocalization(); // 配置请求区域性 var supportedCultures = new[] { new CultureInfo("nl-NL") }; app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("nl-NL"), SupportedCultures = supportedCultures, SupportedUICultures = supportedCultures });
自定义Decimal模型绑定器示例:
public class DecimalModelBinderProvider : IModelBinderProvider { public IModelBinder GetBinder(ModelBinderProviderContext context) { if (context.Metadata.ModelType == typeof(decimal) || context.Metadata.ModelType == typeof(decimal?)) { return new DecimalModelBinder(); } return null; } } public class DecimalModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var value = valueProviderResult.FirstValue; if (string.IsNullOrEmpty(value)) return Task.CompletedTask; if (decimal.TryParse(value, NumberStyles.Any, bindingContext.HttpContext.RequestCulture.Culture, out var result)) { bindingContext.Result = ModelBindingResult.Success(result); } else { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, $"无法将值 {value} 转换为Decimal类型"); } return Task.CompletedTask; } }
DateTime模型绑定器可参照上述逻辑,将解析逻辑替换为DateTime.TryParse并使用请求区域性。
方法2:前端转换为不变区域性格式后提交
在AJAX发送前,手动将荷兰格式的数值和日期转换为不变区域性识别的格式:
- Decimal:把逗号替换为点(如
2,01→2.01) - DateTime:转换为ISO 8601格式(如
30-12-2022→2022-12-30T00:00:00)
示例JS代码:
// 格式化Decimal function formatDecimal(value) { return value.replace(',', '.'); } // 格式化DateTime(输入为dd-MM-yyyy格式) function formatDate(dateStr) { const [day, month, year] = dateStr.split('-'); return `${year}-${month}-${day}T00:00:00`; } // 构造提交数据 const submitData = { Id: 1, Quantity: formatDecimal('2,01'), Date: formatDate('30-12-2022'), // 其他字段... }; // 发送AJAX请求 $.ajax({ url: '/YourPage?handler=Update', type: 'POST', contentType: 'application/json', data: JSON.stringify(submitData), headers: { 'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val() }, success: (res) => { // 处理成功逻辑 } });
方法3:给模型字段添加格式化注解
在UpdateModel的字段上添加[DisplayFormat]属性,明确指定格式和区域性:
public class UpdateModel { public int Id { get; set; } [DisplayFormat(DataFormatString = "{0:N2}", ApplyFormatInEditMode = true, NullDisplayText = "")] [DataType(DataType.Currency)] public decimal Quantity { get; set; } [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)] [DataType(DataType.Date)] public DateTime Date { get; set; } // 其他字段... }
同时确保已在Program.cs中启用本地化和区域性配置(同方法1中的请求区域性配置)。
内容的提问来源于stack exchange,提问作者Bartvandee
相关产品推荐
相关产品推荐

