循环 GetType().GetProperties() 并将每个属性与 asp-for (Razor Pages) 绑定

Posted

技术标签:

【中文标题】循环 GetType().GetProperties() 并将每个属性与 asp-for (Razor Pages) 绑定【英文标题】:Loop through GetType().GetProperties() and bind each property with asp-for (Razor Pages) 【发布时间】:2022-01-13 09:50:03 【问题描述】:

刚刚发现GetType().GetProperties()竟然存在,这样可以用吗?

目标是使用循环来获取特定实体上的所有属性,而无需在 html 中对每个属性进行硬编码,更新每个已编辑的属性并借助 [BindProperty] 注释将新信息保存在 OnPost 中。 我无法正确绑定 asp-for taghelper。

    <form method="post">

       @foreach (var prop in Model.Product.GetType().GetProperties())
       
           <label asp-for="@prop.Name"></label>
           <input asp-for="@prop.GetValue(Model.Product)" class="form-control" />
       
       <button type="submit" class="btn btn-primary">Update</button>

    </form>

运行此代码会出现以下异常:

InvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.

如果我在标签内使用 value="@prop.GetValue(Model.Product)" 我在加载编辑页面时正确获取信息。但是在提交表单时,我没有得到以前输入的新值。

这是模型页面中的模型

[BindProperty]
public ProductModel? Product  get; set; 

OnGet()

   Product = db.GetProduct(id);

感谢您抽出宝贵时间阅读本文!

【问题讨论】:

感谢您的提醒和您提供的答案:) 【参考方案1】:

Tag Helper 帮助我们以声明式编程的风格编写代码。当您发现难以通过反射动态渲染不同的字段时,请尝试使用Html helper 作为替代方式。

如果您只想渲染没有设置值的输入。 Html Helper 工作正常。但是您似乎也想为输入设置值,我尝试了以下方式,但在 asp.net core 3.x 中没有意义:

@Html.Editor(prop.Name, new  htmlAttributes = new  @class = "form-control",@Value=prop.GetValue(Model.Product) )

所以我建议你可以自定义一个标签助手,它设置来自视图中asp-for-model 属性和asp-for-prop 属性的 id 、 name 和输入值。

ConditionTagHelper:

namespace AuthoringTagHelpers.TagHelpers

    [HtmlTargetElement("input", Attributes = "asp-for-prop")]

    public class ConditionTagHelper : TagHelper
    
        [HtmlAttributeName("asp-for-prop")]
        public ModelExpression Property  get; set; 

        [HtmlAttributeName("asp-for-model")]
        public ModelExpression Model  get; set; 


        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        
            var propName = Property.ModelExplorer.Model.ToString();
            var modelName = Model.Name.ToString();
            var modelExProp = Model.ModelExplorer.Properties.Single(x => x.Metadata.PropertyName.Equals(propName));
            var propValue = modelExProp.Model;

            var para = modelName + "." + propName;

            output.Attributes.Add("id", para);
            output.Attributes.Add("name", para);
            output.Attributes.Add("value", propValue);

            base.Process(context, output);
        
    

在 _viewImports.cshtml 中:

@addTagHelper *, AuthoringTagHelpers   //AuthoringTagHelpers depends on your project name

注意@addTagHelper 之后的第一个字符串指定要加载的标签助手(所有标签助手使用“*”),第二个字符串AuthoringTagHelpers 指定标签助手所在的程序集在。

页面:

<form method="post">

    @foreach (var prop in Model.Product.GetType().GetProperties())
    
        @Html.Label(prop.Name)
        <input asp-for-model="@Model.Product" asp-for-prop="@prop.Name" class="form-control" />
    
    <button type="submit" class="btn btn-primary">Update</button>

</form>

【讨论】:

你好瑞娜!非常感谢您的回复。我通过执行自定义 ViewModel(类)并在 OnGet 中使用 GetType().GetProperties() 填充 ViewModelClass 列表来解决它。我对您的方法进行了快速尝试,但无法使其正常工作,它似乎没有绑定列表,当我到达 OnPost 时,列表再次为空。但它确实让我深入了解了如何创建自定义标签助手,谢谢! 使用这个名字:@Html.Label($"nameof(Model.InputModel).prop.Name") @Html.Editor($"nameof(Model.InputModel).prop.Name", new htmlAttributes = new @class = "form-control",@Value=prop.GetValue(Model.InputModel) )

以上是关于循环 GetType().GetProperties() 并将每个属性与 asp-for (Razor Pages) 绑定的主要内容,如果未能解决你的问题,请参考以下文章

C# 反射 GetType() 异常

GetType obsolete

GetType、typeof 和 is,处理 null 和转换 [重复]

为啥我无法获取 GetType() 的 MethodBody?

Type.GetType()在跨程序集反射时返回null

何时何地使用 GetType() 或 typeof()? [复制]