ASP.NET Razor中Tempus Dominus日期选择器值无法绑定回传模型
问题根因
核心是前端提交的日期字符串格式和后端.NET Framework 4.8默认模型绑定的解析规则不匹配,叠加页面脚本加载、组件引用的几个低级错误,最终导致绑定失败:
- 你前端日期选择器配置的显示格式是
dd/mm/yyyy(土耳其区域常用的日/月/年格式),原生表单提交时会把输入框里的文本原封不动传给后端。但.NET Framework默认用当前服务器的区域设置解析DateTime,如果服务器没配置tr-TR区域,默认会按MM/dd/yyyy(月/日/年)格式解析,遇到类似15/06/2024这种第一个数大于12的日期会直接解析失败,模型绑定器就会给字段赋DateTime.MinValue默认值。
你用AJAX提交能正常拿到值,是因为AJAX提交时要么手动做了格式转换,要么序列化时用了JS默认的ISO日期格式(yyyy-MM-ddTHH:mm:ss),后端能正常识别,和表单提交传的原始文本不是一个东西。 - 页面脚本顺序完全错误:jQuery是所有插件的依赖,你把Bootstrap5的JS放在jQuery前面加载,会导致所有依赖jQuery的插件初始化异常。
- 日期组件引用混乱:你用的是Bootstrap5框架,却加了Bootstrap4版本的Tempus Dominus日期选择器,俩版本本身不兼容;而且你同时引了jQuery UI的datepicker组件,两个组件都占用
.datepicker()方法名,后加载的会覆盖前一个。更关键的是Tempus Dominus的初始化方法是.datetimepicker()不是.datepicker(),等于你引了Tempus Dominus的资源根本没用上,实际生效的是jQuery UI的datepicker。 - 初始化选择器写法错误:你写的
$(txtStoveInstalledDate)没加id选择器的#前缀,正常情况下会直接报JS变量未定义的错误,你那边日期选择器能正常交互,要么是实际运行代码补了#,要么是页面其他地方定义了同名DOM变量。
修复步骤
按优先级从高到低改:
- 先修正脚本加载顺序,必须把jQuery放在所有依赖它的组件最前面,调整后顺序参考:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-ajax-unobtrusive/3.2.6/jquery.unobtrusive-ajax.min.js" integrity="sha512-DedNBWPF0hLGUPNbCYfj8qjlEnNE92Fqn7xd3Sscfu7ipy7Zu33unHdugqRD3c4Vj7/yLv+slqZhMls/4Oc7Zg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> <script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script> <!-- 删掉不兼容的Tempus Dominus引用,你实际用的是jQuery UI datepicker,不需要加这个资源 --> - 修正后端日期解析规则,从根源解决格式不匹配问题,两种方案选一个就行:
- 方案一(全局生效,最省事):在项目
web.config的<system.web>节点下加全局区域配置,指定用土耳其区域解析日期:<globalization culture="tr-TR" uiCulture="tr-TR"/> - 方案二(只针对单个字段):在ViewModel的日期字段上加格式特性,指定绑定/显示时用dd/MM/yyyy格式:
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateTime StoveInstalled { get; set; }
- 方案一(全局生效,最省事):在项目
- 修正日期选择器初始化代码,补上id选择器的
#前缀:$(function () { $('#txtStoveInstalledDate').datepicker({ changeMonth: true, changeYear: true, format: "dd/mm/yyyy", language: "tr" }); }); - 额外验证:打开浏览器F12看表单提交时的Form Data,确认
StoveInstalled字段确实提交了dd/mm/yyyy格式的值,且渲染出的input的name属性是StoveInstalled(如果是嵌套模型要对应调整name前缀,不过你AJAX能正常提交,这步大概率没问题)。
注:readonly属性不会影响表单提交值,只有disabled属性的字段才不会被表单提交,你之前测了移除readonly没用,就不用在这个属性上浪费时间排查。
内容的提问来源于stack exchange,提问作者Jim Tench
相关产品推荐
相关产品推荐

