Razor Pages中DateOnly与TimeOnly绑定HTML日期时间控件问题
解决Razor Pages中DateOnly/TimeOnly与HTML日期时间控件的绑定问题
问题描述
使用MariaDB作为数据库,在Razor Pages中为用户提供日期选择器(type="date")和时间选择器(type="time")控件时,无法将DateOnly和TimeOnly字段正确绑定到这些HTML控件。
现有代码
视图代码
<form method="post"> <input hidden asp-for="Period.Periodid" /> <div class="border p-3 mt-4"> <div class="row mb-3"> <h4 class=" pl-3">Επεξεργασία Επαφής</h4> </div> <div asp-validation-summary="All" class="text-danger"></div> <div class="mb-3"> <label asp-for="Period.StartDate">Ημερομηνία Έναρξης</label> <input type="date" asp-for="Period.StartDate" class="form-control" /> <span asp-validation-for="Period.StartDate" class="text-danger"></span> </div> <div class="mb-3"> <label asp-for="Period.EndDate">Ημερομηνία Λήξης</label> <input type="date" asp-for="Period.EndDate" class="form-control" /> <span asp-validation-for="Period.EndDate" class="text-danger"></span> </div> <div class="mb-3"> <label asp-for="Period.StartTime">Ώρα Έναρξης</label> <input type="time" asp-for="Period.StartTime" class="form-control" /> <span asp-validation-for="Period.StartTime" class="text-danger"></span> </div> <div class="mb-3"> <label asp-for="Period.EndTime">Ώρα Λήξης</label> <input type="time" asp-for="Period.EndTime" class="form-control" /> <span asp-validation-for="Period.EndTime" class="text-danger"></span> </div> <button type="submit" class="btn btn-primary" style="width:150px;">Ενημέρωση</button> <a asp-page="Index" class="btn btn-secondary" style="width:150px;">Λίστα</a> </div>
模型代码
public class Period { public int Periodid { get; set; } [Required] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateOnly StartDate { get; set; } [Required] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)] public DateOnly EndDate { get; set; } [Required] [DataType(DataType.Time)] public TimeOnly StartTime { get; set; } [Required] [DataType(DataType.Time)] public TimeOnly EndTime { get; set; } }
解决方案
1. 修正模型的DisplayFormat格式
HTML的date控件要求输入/输出的日期格式为yyyy-MM-dd(浏览器会自动转为本地格式显示,但绑定必须用标准格式);time控件要求格式为HH:mm:ss或HH:mm。修改模型的DisplayFormat:
public class Period { public int Periodid { get; set; } [Required] [DataType(DataType.Date)] // 适配HTML date控件的标准格式 [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateOnly StartDate { get; set; } [Required] [DataType(DataType.Date)] [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateOnly EndDate { get; set; } [Required] [DataType(DataType.Time)] // 适配HTML time控件的标准格式 [DisplayFormat(DataFormatString = "{0:HH:mm:ss}", ApplyFormatInEditMode = true)] public TimeOnly StartTime { get; set; } [Required] [DataType(DataType.Time)] [DisplayFormat(DataFormatString = "{0:HH:mm:ss}", ApplyFormatInEditMode = true)] public TimeOnly EndTime { get; set; } }
2. 添加DateOnly/TimeOnly的模型绑定器(ASP.NET Core 6及更早版本)
ASP.NET Core 7+已原生支持DateOnly/TimeOnly的模型绑定,若使用更早版本,需手动实现绑定器:
第一步:注册绑定器
在Program.cs中添加:
builder.Services.AddRazorPages() .AddMvcOptions(options => { options.ModelBinderProviders.Insert(0, new DateOnlyModelBinderProvider()); options.ModelBinderProviders.Insert(1, new TimeOnlyModelBinderProvider()); });
第二步:实现绑定器类
// DateOnly绑定器提供类 public class DateOnlyModelBinderProvider : IModelBinderProvider { public IModelBinder? GetBinder(ModelBinderProviderContext context) { if (context.Metadata.ModelType == typeof(DateOnly) || context.Metadata.ModelType == typeof(DateOnly?)) { return new DateOnlyModelBinder(); } return null; } } // DateOnly绑定器 public class DateOnlyModelBinder : 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)) { bindingContext.Result = ModelBindingResult.Success(null); return Task.CompletedTask; } if (DateOnly.TryParse(value, CultureInfo.InvariantCulture, out var date)) { bindingContext.Result = ModelBindingResult.Success(date); } else { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "无效的日期格式"); } return Task.CompletedTask; } } // TimeOnly绑定器提供类 public class TimeOnlyModelBinderProvider : IModelBinderProvider { public IModelBinder? GetBinder(ModelBinderProviderContext context) { if (context.Metadata.ModelType == typeof(TimeOnly) || context.Metadata.ModelType == typeof(TimeOnly?)) { return new TimeOnlyModelBinder(); } return null; } } // TimeOnly绑定器 public class TimeOnlyModelBinder : 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)) { bindingContext.Result = ModelBindingResult.Success(null); return Task.CompletedTask; } if (TimeOnly.TryParse(value, CultureInfo.InvariantCulture, out var time)) { bindingContext.Result = ModelBindingResult.Success(time); } else { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "无效的时间格式"); } return Task.CompletedTask; } }
3. 数据库层面适配(MariaDB)
确保EF Core将DateOnly映射到MariaDB的DATE类型,TimeOnly映射到TIME类型,在DbContext的OnModelCreating中配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Period>() .Property(p => p.StartDate) .HasColumnType("DATE"); modelBuilder.Entity<Period>() .Property(p => p.EndDate) .HasColumnType("DATE"); modelBuilder.Entity<Period>() .Property(p => p.StartTime) .HasColumnType("TIME"); modelBuilder.Entity<Period>() .Property(p => p.EndTime) .HasColumnType("TIME"); }
验证
完成以上配置后,重新运行项目:
- 日期选择器会正确显示
DateOnly字段的值,提交后能正确绑定回模型 - 时间选择器同理,可正常读取和提交
TimeOnly值
内容的提问来源于stack exchange,提问作者snikos
相关产品推荐
相关产品推荐

