Razor foreach 在 id 中放置 property/variable 名称,在呈现的 HTML 中放置 *for 属性

Razor foreach placing property/variable name in id,name and *for attributes in rendered HTML

工具与平台:ASP.NET Core MVC 3.1,Visual Studio 2019,Win 10

更新:这是一个 Upsert 视图。 我正在尝试遍历 Razor 页面中模型的属性以生成标签并在表单标记内输入 HTML 元素,但呈现的 HTML 具有 "Item" (名称foreach 中的变量)作为 id、name 和 *for HTML 属性的值。

在浏览器中呈现 HTML

<div class="form-group row">
  <div class="col-3">
    <label for="item">item</label>
  </div>
  <div class="col-6">
    <input class="form-control" type="text" id="item" name="item" value="Author">
    <span class="text-danger field-validation-valid" data-valmsg-for="item" data-valmsg-replace="true"></span>
  </div>
</div>

HTML在浏览器中显示

Razor foreach 循环产生 HTML

 @{ var propList = new string[] { "Name", "Author", "ISBN" };}
 @foreach (var item in propList)
    {
        <div class="form-group row">
            <div class="col-3">
                <label asp-for="@item"></label>
            </div>
            <div class="col-6">
                <input asp-for="@item" class="form-control" />
                <span asp-validation-for="@item" class="text-danger"></span>
            </div>
        </div>
    }

有人可以解释为什么会这样吗?

更新:
根据“@Ben Sampica”的建议,我进行了这些更改, 我的视图会是什么样子,我的意思是我记得使用模型列表作为 table 类视图(几年前我使用过 ASP.NET MVC,现在跳转到 .net 核心),这里是更改我做了,

查看:

@foreach (var book in Model.Books)
  {
    <div class="form-group row">
      <div class="col-3">
        <label asp-for="@book.Name"></label>
      </div>
      <div class="col-6">
        <input asp-for="@book.Name" class="form-control" />
        <span asp-validation-for="@book.Name" class="text-danger"></span>
      </div>
    </div>
  }

我正在使用您描述的确切视图模型"BooksViewModel"

我之前没有在问题中说明,但要明确我正在创建一个 Upsert 视图,所以现在 ViewModel 是一个列表,尽管我一次只关心一个记录,视图创建操作时模型为空,因为列表中没有数据。

如果您查看 Microsoft Docs on ASP.NET Core Tag Helpers,您会发现 <label> 上的 asp-for 会从 属性 中获取 [Display] 属性(如果当前的)。作为备份,它将使用 属性 名称。在您的例子中,您传递的是一个字符串集合,所以让我们深入了解 Razor 看到的内容

PropList[]
{
    string item = "Name"
    string item = "Author"
    string item = "ISBN"
}

迭代时,没有 Display 属性,那么根据我们上面的规则,约定是什么?使用 属性 名称(您在迭代器中将其命名为 item)。

我认为您尝试做的事情在专用模型class中可能会更好地完成,例如:

public class BookViewModel
{
   public string Name { get; set; }
   public string Author { get; set; }
   public string ISBN { get; set; }
}

那么在你看来

@using BookViewModel

<form>
    <div class="form-group row">
      <div class="col-3">
        <label asp-for="@Model.Name"></label>
      </div>
      <div class="col-6">
        <input asp-for="@Model.Name" class="form-control" />
        <span asp-validation-for="@Model.Name" class="text-danger"></span>
      </div>
    </div>
    <div class="form-group row">
      <div class="col-3">
        <label asp-for="@Model.Author"></label>
      </div>
      <div class="col-6">
        <input asp-for="@Model.Author" class="form-control" />
        <span asp-validation-for="@Model.Author" class="text-danger"></span>
      </div>
    </div>
    <div class="form-group row">
      <div class="col-3">
        <label asp-for="@Model.ISBN"></label>
      </div>
      <div class="col-6">
        <input asp-for="@Model.ISBN" class="form-control" />
        <span asp-validation-for="@Model.ISBN" class="text-danger"></span>
      </div>
    </div>
    <button type="submit">Submit</button>
</form>

更新响应:
以下回复来自 chat conversation b/w op 和 Answer poster

  1. 如果我正在做这个,我只会做两个动作(添加和编辑)并共享表单输入的部分视图,以便尽可能多地重用代码 - 而不是对这个 upsert 的解决方案太聪明了。这只是我的意见。我认为这就是为什么我无法理解您要查找的内容的部分原因。

  2. 我也不会用反射之类的东西来写HTML。如果你想重用一种输入类型(如文本框)的总体布局,我最多会制作一个视图组件并传递 属性。我不会 @foreach 整个模型 - 你如何确定下拉列表是什么?复选框呢?使用无法维护的巧妙解决方案,您很快就会陷入非常糟糕的境地。

最后,

  1. 如果您仍然想继续 - 最初通过反射走在正确的轨道上 - 请参阅以下 dotnet fiddle。忽略编译器警告并将@foreach 块复制到您自己的项目中。

Foreach on the View Model