如何将 ModelExpression 绑定到 ASP.NET Core 中的 ViewComponent? [英] How to bind a ModelExpression to a ViewComponent in ASP.NET Core?

本文介绍了如何将 ModelExpression 绑定到 ASP.NET Core 中的 ViewComponent?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将模型表达式(例如属性)绑定到视图组件——就像我使用 HTML 帮助程序(例如,@Html.EditorFor())或标签一样帮助器(例如,)——在带有嵌套 HTML 和/或标签帮助器的视图中重用此模型.我能够将 ModelExpression 定义为视图组件上的参数,并从中检索许多有用的元数据.除此之外,我开始遇到障碍:

  • 我如何中继和绑定到底层源模型,例如asp-for 标签助手?
  • 如何确保来自 ViewData.ModelMetadata 的属性元数据(例如验证属性)得到尊重?
  • 如何为字段name 属性组装完全限定 HtmlFieldPrefix?

我提供了一个(简化的)场景,其中包含下面的代码和结果——但代码暴露的未知数多于答案.已知大部分代码是不正确的,但我将其包含在内,以便我们可以有一个具体的基线来评估和讨论替代方案.

场景

asp-for 标签助手,那么它会自动启用 multiple,是绑定到集合模型时的默认行为.

/Views/Shared/Select/Default.cshtml

@model SelectViewModel<select asp-for=@Model asp-items="Model.Options"><option value="">选择一个...</option></选择>

注意事项

  • 从技术上讲,@Model 的值将返回 SelectViewModel.如果这是一个 ,那将是显而易见的.由于 SelectList 识别了正确的值,大概是从 ViewData.ModelMetadata 中识别出来的,这个问题被掩盖了.
  • 我可以将 aspFor.Model 设置为例如SelectViewModel 上的 UnderlyingModel 属性.这将导致 {HtmlFieldPrefix}.UnderlyingModel 的 HTML 字段名称 - 并且仍然无法从原始属性中检索任何元数据(例如验证属性).

变化

如果我不设置 HtmlFieldPrefix,并将视图组件放在例如的上下文中@Html.EditorFor() 然后字段名称将是正确的,因为 HtmlFieldPrefix 正在被定义在父上下文中.但是,如果我将其直接放在顶级视图中,则会由于未定义 HtmlFieldPrefix 而出现以下错误:

<块引用>

ArgumentException:HTML 字段的名称不能为 null 或为空.而是使用具有非空 htmlFieldName 参数值的 Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper.Editor 或 Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper``1.EditorFor 方法.(参数'表达式')

问题

  • HtmlFieldPrefix 未正确填充完全限定的值.例如,如果模型属性名称是 Country,它将始终返回 Country,即使实际模型路径是,例如,ShippingAddress.Country地址[2].国家.
  • jQuery Validation Unobtrusive 功能未触发.例如,如果绑定到的属性被标记为 [Required] 那么这里就不会被标记.这大概是因为它被绑定到 SelectViewModel,而不是父属性.
  • 原始模型不会以任何方式中继到视图组件的视图;SelectList 能够从 ViewData 推断出原始值,但是这在视图中丢失了.我可以通过视图模型中继 aspFor.Model,但它无法访问原始元数据(例如验证属性).

替代选项

我考虑过的一些其他选项,但在我的用例中被拒绝.

  • 标签助手:这很容易通过标签助手实现.将依赖项(例如存储库)注入标签助手不太优雅,因为没有办法通过组合根实例化标签助手,例如可以这样做IViewComponentActivator.
  • 控制器:在这个简化的例子中,还可以在顶级视图模型上定义源集合,紧邻实际属性(例如,Country为值,CountryList 为选项).在更复杂的示例中,这可能不实用或不优雅.
  • AJAX: 可以通过对 Web 服务的 JavaScript 调用检索值,将 JSON 输出绑定到客户端上的 <option value="">选择一个...</option></选择>

    这可能会返回正确的 idname 属性,因为它会回退到 ViewDataHtmlFieldPrefix>.但是,它不会访问任何例如数据验证属性,因为它绑定到 SelectViewModel 而不是对原始 UserViewModel.Country 属性的引用,就像在编辑器模板.

    同样,您可以通过例如传递ModelExpression.Model一个 SelectViewModel.Model 属性...

    
                    
                
发送“验证码”获取 | 15天全站免登陆