ASP.NET MVC / Razor:使用带有字符串字段的日期选择器

问题描述 投票:0回答:1

我的模型中有以下“日期”字段,它们表示为字符串:

enter image description here

enter image description here

我的看法如下:

enter image description here

enter image description here

我的问题是如何正确转换字符串以适合日期选择器?

我不确定是否应该在模型或视图中完成。

asp.net-mvc razor
1个回答
0
投票

我的教宗观点没有特定的排列:

  • 当有更好的值类型可用时,不要使用
    String
      在这种情况下,
    • 您应该使用 DateOnly?
      (又名 
      Nullable<DateOnly>
      )。
      
      应该使用
      • Nullable<T>
        ,因为它允许 
        日期输入,而 <input type="date" value="" />
         允许,而在使用 ASP.NET 的模型绑定时,不可为空的 
        DateOnly
         视图模型属性更难使用,因为 
        任何表单字段可以为空或无效,或者只是普通的未定义。您可能认为 [Required]
         属性解决了这个问题,但事实并非如此:
        [Required]
         属性 
        不会阻止属性为空,它只是在属性为空时阻止 ModelStateDictionary.IsValid
         返回 
        true
        ,这意味着您始终需要正确(如果不是优雅地)处理空/未定义的表单字段,并将其与值类型的 
        default(T)
        区分开来(例如
        default(DateOnly)
        是 .
        
        
      即使您的底层数据库不幸地错误地存储了日期,但这并不能阻止您在应用程序代码中使用适当的类型。
    • 如果您使用从现有数据库生成的 EF 实体类,那么这不是借口,因为
        您不应该将 EF 实体类与 ASP.NET 表单绑定一起使用
      • ,而是应该定义一个单独的 class MyPageViewModel,它可以公开
        DateOnly?
        参数。
        
        
    HTML
  • <input type="date" />
  • 要求
    value="" 参数格式为
    yyyy-MM-dd
    HTML-Helpers 如今实际上已经过时,请考虑使用 Tag-Helpers。
    
  • 使用
      <input asp-for="YMDEFF" type="date" />
    • 而不是
      Html.TextBoxFor
        asp-for=""
      • 是一个
        special
        ModelExpression 属性,就像
        TextBoxFor
        Expression<>
        参数一样,它用于在运行时生成
        id=""
        name=""
        属性。
        
        
    出于对程序正确性的热爱,请永远不要这样做
  • public String SomeProperty { get; } = null!
  • -
    它在很多层面上都是错误的
    如果一个
      String
    • 属性
      can
      曾经是 null 那么它的类型
      must
      String? - 而不是
      String
      - 并且对
      null
      的初始化只是多余的。
      如果 
    • String
    • 属性永远不会是
      null
      ,则将其初始化为
      = String.Empty
      = ""
      ,而不是
      null!
      yikes
    请勿使用全大写名称,如
  • YMDEFF
  • YMDEND
    - 在 C#/.NET 中,我们使用
    PascalCase
    camelCase
    ,这样所有 3 个字母或更长的单词和首字母缩略词始终为 
    TitleCase
    ,而所有 2 字母缩写始终为大写(如
    IO
    ),而 2 字母缩写(如“Database”的
    Db
    )则不是。
    现在 
      YMDEFF
    • 看起来像“YMD Eff...”,我假设
      YMD
      指的是日期格式,而“Eff”是“Effective”的缩写,所以只需将其命名为
      EffectiveDate
      并且
    • YMDEND
    • 看起来像“YMD End”,按照同样的逻辑,这应该被命名为
      EndDate
      
      
  • 像这样:

public class MyPageViewModel { // [Required] // <-- Uncomment or delete this line, based on your actual requirements. [DisplayFormat( DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true )] // <-- This attribute is necessary to ensure the `<input value=""/>` attribute has the correct format that HTML requires. public DateOnly? EffectiveDate { get; set; } // [Required] [DisplayFormat( DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true )] public DateOnly? EndDate { get; set; } }

您的 Razor 标记可能如下所示:

@model MyPageViewModel // etc <form asp-controller="Foobar" asp-action="Post"> <div class="field"> <label asp-for="EffectiveDate"></label> <input asp-for="EffectiveDate" type="date" /> <span asp-validation-for="EffectiveDate"></span> </div> <div class="field"> <label asp-for="EndDate"></label> <input asp-for="EndDate" type="date" /> <span asp-validation-for="EndDate"></span> </div> <button type="submit">Submit</button> </form>

您的控制器操作将保存数据库(令人讨厌的)基于
String

的日期和

DateOnly
日期之间的编组逻辑:
[HttpGet( "/my-form" )]
public async Task<IActionResult> GetForm()
{
    SomeEntityClass e = await this.db.GetThingAsync();

    MyPageViewModel vm = new MyPageViewModel()
    {
        EffectiveDate = DateOnly.TryParseExact( format; "yyyyMMdd", value: e.YMDEFF, out DateOnly parsed ) ? parsed : (DateOnly?)null,
        EndDate       = DateOnly.TryParseExact( format; "yyyyMMdd", value: e.YMDEND, out DateOnly parsed ) ? parsed : (DateOnly?)null
    };

    return this.View( model: vm );
}

[HttpPost( "/my-form" )]
public async Task<IActionResult> PostForm( [FromForm] MyPageViewModel model )
{
    SomeEntityClass e = await this.db.GetThingAsync();

    if( !this.ModelState.IsValid ) return this.View( model: model );
    Debug.Assert( model.EffectiveDate.HasValue ); // <-- This is to workaround how the C# compiler isn't aware that `ModelState.IsValid` indicates (for example) non-nullability of those View-Model properties.
    Debug.Assert( model.EndDate.HasValue );

    //

    e.YMDEFF = model.EffectiveDate.Value.Tostring( format: "yyyyMMdd" );
    e.YMDEND = model.EndDate      .Value.Tostring( format: "yyyyMMdd" );

    await this.db.SaveChangesAsync();

    return this.RedirectToAction( nameof(GetForm) );
}

	
© www.soinside.com 2019 - 2024. All rights reserved.