使用反射和Razor Tag Helper .Net 3.1渲染MVC表单

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

我想创建复杂的表单,它将创建向导的结构,部分步骤的表单,验证并提交。该结构必须使用模型属性批注在模型上创建一个结构对象。因此,经过反思,我得到了带有结构描述的模型和另一个类。内的所有属性都是带有字段的字符串,我必须传递“ asp-for”标签帮助程序。因此,部分代码是:

@foreach(var field in @group.Fields) {
  <div class="col-12 col-md-6 col-lg-4">
     <div class="form-group md-form md-outline">
        <label asp-for="@field.Name" class="control-label"></label>
        <input asp-for="@field.Name" class="form-control" />
        <span asp-validation-for="@field.Name" class="text-danger"></span>
     </div>
  </div>  
}

这是行不通的,因为标签帮助程序期望表达式并生成我不期望的错误值。 @ field.Name中的值为“ PostAddress.Street1”。如果我将所有“ @ field.Name”替换为“ PostAddress.Street1”,那么一切将按预期正常运行。Fields render

这看起来很小,但我正在尝试很多事情,并在论坛上阅读了一些广告,但没有找到答案。我试过的:

  1. 实验1

试图从dotnet库继承InputTagHelper类,并覆盖For的属性,但没有成功。它更改了ModelExpression,但没有更改接口。可能是基类具有跳过此更改的对象的某些逻辑,或者生成的逻辑不正确:

[HtmlAttributeName("asp-for")]
    public new ModelExpression For
    {
        get
        {
            return base.For;
        }
        set
        {
            ModelExpression me = value;
            if (value.Model != null)
            {
                var viewData = this.ViewContext.ViewData as ViewDataDictionary<AbnServiceModel>;

                me = ModelExpressionProvider.CreateModelExpression<AbnServiceModel, string>(viewData, model => model.PostAddress.Street1);
            }
            base.For = me;
        }
    }

================================================ = 2.实验2

尝试从.NET Core代码获取原始实现,并对代码进行了一些修改以解决此问题。但是内部库的代码和依赖性非常复杂,我拒绝这个想法。

  1. 实验3使用HTML帮助器

@Html.Label(@field.Name, "", new{ @class="control-label" })
@Html.Editor(@field.Name,  new { htmlAttributes = new{ @class="form-control" } })
@Html.ValidationMessage(@field.Name,"",new { htmlAttributes = new{ @class="text-danger" } })

它使组件正确地进入浏览器,但是使用jquery.validate.unobtrusive.js的客户端验证不起作用。不知道为什么。

  1. 实验4使用HTML帮助器:

@Html.LabelFor(m=>m.PostAddress.Street1, new{ @class="control-label" })
@Html.EditorFor(m=>m.PostAddress.Street1,  new { htmlAttributes = new{ @class="form-control" } })
@Html.ValidationMessageFor(m=>m.PostAddress.Street1,"",new { htmlAttributes = new{ @class="text-danger" } })

[验证工作正常,但是上课没有很好地应用,可能是我的错误。但是这里的另一个问题是我没有使用可以从模型对象获得的字符串表达式。同样,它不能捕获asp-for标记助手中包含的所有逻辑。

  1. 实验5试图创建我自己的标签助手,并使用生成器来创建内容html。但这意味着我必须在dotnet核心中实现所有逻辑(如助手),才能具有与实验2
  2. 相同的所有功能。

因此,我没有找到解决此“简单”问题的好方法,并且花了几天的时间进行调查并编写一些代码来解决该问题。我很惊讶没有办法传递带有属性名的字符串变量,而且行不通。

有人可以通过实际示例帮助我解决此问题吗?我没有在所有帖子中都找到答案。我想从asp-for标签助手获得所有逻辑,但要使用变量来传递表达式。它很棘手,只是想拥有一些分辨率才能继续我的项目。

谢谢

asp.net-mvc forms razor .net-core tag-helpers
1个回答
0
投票

我解决了我的问题。创建了一个辅助方法:

public static class CommonHelperMethods
    {
        public static ModelExplorer GetModelExplorer(this ModelExplorer container, string field, IModelMetadataProvider modelMetadataProvider = null)
        {
            ModelExplorer result = container;
            var fields = field.Split(".").ToList();

            var match = Regex.Match(fields[0], @"(.+)\[(\d)+\]");
            if (!match.Success)
            {
                fields.ForEach(x =>
                {
                    result = result?.GetExplorerForProperty(x) ?? result;
                });
            }
            else
            { //List have to create own Property browser
                string proName = match.Groups[1].Value;
                int idx = Convert.ToInt32(match.Groups[2].Value);
                var model = ((IList)result?.GetExplorerForProperty(proName).Model)[idx];
                var targetProperty = model.GetType().GetProperty(fields[1]);
                var targetValueModel = targetProperty.GetValue(model);


                var elementMetadata = modelMetadataProvider.GetMetadataForProperty(model.GetType(), fields[1]);
                return new ModelExplorer(modelMetadataProvider, container, elementMetadata, targetValueModel);
            }    
            return result;
        }
    }

并且只需使用以下方法覆盖标记帮助程序类:

using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace GetTaxSolutions.Web.Infrastructure.TagHelpers
{
    [HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
    public class InputTextGtTaxHelper : InputTagHelper
    {
        private const string ForAttributeName = "asp-for";
        [HtmlAttributeName("not-exp")]
        public bool NotExpression { get; set; } = false;

        [HtmlAttributeName(ForAttributeName)]
        public new ModelExpression For
        {
            get
            {
                return base.For;
            }
            set
            {
                ModelExpression me = value;
                if (NotExpression)
                {
                    var modelExplorertmp = value.ModelExplorer.Container.GetModelExplorer(value.Model.ToString(), ModelMetadataProvider);
                    var modelExplorer = new ModelExplorer(ModelMetadataProvider, value.ModelExplorer.Container, modelExplorertmp.Metadata, modelExplorertmp.Model);
                    me = new ModelExpression(value.Model.ToString(), modelExplorer);
                }
                base.For = me;
            }
        }

        public IModelExpressionProvider ModelExpressionProvider { get; }
        public IModelMetadataProvider ModelMetadataProvider { get; }
        public IActionContextAccessor Accessor { get; }

        public InputTextGtTaxHelper(
            IHtmlGenerator generator,
            IModelExpressionProvider modelExpressionProvider,
            IModelMetadataProvider modelMetaDataProvider) : base(generator)
        {
            ModelExpressionProvider = modelExpressionProvider;
            ModelMetadataProvider = modelMetaDataProvider;
        }
    }
}

也应跳过标签帮助程序注册中的原始类:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.InputTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.LabelTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.ValidationMessageTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.SelectTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper GetTaxSolutions.Web.Infrastructure.TagHelpers.*, GetTaxSolutions.Web

并且在表达式中使用模型时,只需在输入元素上传递属性'no-exp'。否则,它将像原始标签助手一样工作。

<input not-exp="true" asp-for="@field.Name" class="form-control" />

此外,您还需要使用标签,选择和其他您要支持这种模型传递方式的二手标签助手。

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