【问题标题】:Create Custom HTML Helper in ASP.Net Core在 ASP.Net Core 中创建自定义 HTML Helper
【发布时间】:2017-06-21 17:04:40
【问题描述】:

我想创建我自己的自定义 HTML Helper,就像在 ASP.NET MVC 中使用的那些一样,但我无法找到如何以正确的方式实现它们。

我发现了如何创建自定义标签助手,但不是 HTML 助手。如何创建自己的自定义 HTML 助手?

【问题讨论】:

    标签: asp.net-core asp.net-core-mvc


    【解决方案1】:

    Danny van der Kraan 在他的blog post here 中对此进行了很好的解释。下面的答案是这篇文章的摘录:

    ASP.NET Core 1.0 [MVC 6] 带有一个令人兴奋的新功能,称为TagHelpers。在ASP.Net Core 1.0 中没有像 MVC 中那样的 HTML Helper 的概念。

    什么是 TagHelper?

    TagHelpers 可以看作是随着第一个 MVC 框架的推出而引入的 HTML 助手的演变。为了提供上下文,您必须想象使用经典 ASP,您可以自动生成 HTML 的唯一方法是通过自定义子例程。在那之后,ASP.NET 附带了服务器控件,其中视图状态是最大的优势,以模拟桌面应用程序的外观和感觉并帮助桌面开发人员进行过渡。但是我们都知道当我们试图将方块塞进圆孔时会发生什么。我们不得不面对这样一个事实,即 Web 开发与桌面开发完全不同。为了与正确的 Web 开发保持一致,ASP.NET MVC 框架与 HTML 帮助程序一起启动,以自动化 HTML 输出。但是 HTML 助手从来没有真正凝聚在一起,尤其是前端开发人员和设计人员。主要的烦恼之一是,它让你在视图工作期间从尖括号(HTML, CSS) 切换到C# (Razor syntax),这让体验不必要地不舒服。 [MVC 6] 想通过引入 TagHelpers 来解决这个问题和一些较小的问题。例子 HTML 助手:

    @Html.ActionLink(”Home”, ”Index”, ”Home”)
    

    使用锚 TagHelper 如下所示:

    <a asp-action="Index" asp-controller="Home">Home</a>
    

    PS: 请注意 asp- 只是一个约定,稍后会详细介绍。

    两者在浏览器中呈现的输出是相同的:

    <a href="/">Home</a>
    

    PS: 前提是默认路由没有改变。

    更多关于TagHelpersclick here的信息

    【讨论】:

    • 我知道 TagHelpers 是一个很棒的新功能,但我需要使用类似于 @Html.Raw 的帮助器在视图中插入 HTML。我可以用 TagHelpers 做到这一点吗?
    • TagHelperASP.Net core 的改进功能。您可以使用TagHelper 完成所有操作。但你究竟是想用一些例子来解释?
    • 谢谢@Manish,我不理解 TagHelpers 并且不需要 HtmlHelpers。我找到了一个很好的文档来解决我的问题:link
    • @MANISHKUMARCHOUDHARY 请阅读the following post,了解正确归属您的来源。您帖子底部的链接是不够的。从他人那里复制内容时,应预先给出适当的归属。
    • @spender 感谢您指出我的错误,我已经更新了我的答案。
    【解决方案2】:

    HTML Helpers 看起来在 ASP.NET Core 中受支持,正在等待文档:

    https://docs.microsoft.com/en-au/aspnet/core/mvc/views/html-helpers

    [编辑:]自从回答后,上面的页面不再存在。我想说的是 HTML Helpers,虽然它们工作,但在 ASP.NET Core 中不再“支持”。

    查看 ASP.NET Core 源代码,它们的工作方式与旧版本的 ASP.NET MVC 非常相似:

    https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.ViewFeatures/src/Rendering/HtmlHelperDisplayExtensions.cs


    示例

    MyHTMLHelpers.cs:

    using Microsoft.AspNetCore.Html;
    using Microsoft.AspNetCore.Mvc.Rendering;
    using System;
    
    namespace MyApp.Helpers
    {
        public static class MyHTMLHelpers
        {
            public static IHtmlContent HelloWorldHTMLString(this IHtmlHelper htmlHelper)
                => new HtmlString("<strong>Hello World</strong>");
    
            public static String HelloWorldString(this IHtmlHelper htmlHelper)
                => "<strong>Hello World</strong>";
        }
    }
    

    _ViewImports.cshtml(第二行是重要的变化):

    @using MyApp
    @using MyApp.Helpers
    @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
    

    MyView.cshtml:

    <div>@Html.HelloWorldHTMLString()</div>
    <div>@Html.HelloWorldString()</div>
    

    输出:

    你好世界

    你好世界

    【讨论】:

    • Src 代码链接旧 (404)。当前链接是:github.com/aspnet/AspNetCore/blob/master/src/Mvc/…
    • 这应该在 ms 帮助和文档页面上,甚至还没有累,但我可以说这就是我想要的。 grrrr ms 用这样的例子更新你的东西。
    • 哇,这很容易,但我和 Google 花了一个小时才找到。需要使用剃刀视图模板在 dotnetcore 2.2 中输出原始 html 以发送电子邮件。
    【解决方案3】:

    我从来没有让 HtmlHelper 扩展方法工作,我总是收到:

    “IHtmlHelper”不包含“MethodName”的定义,并且找不到接受“IHtmlHelper”类型的第一个参数的扩展方法“MethodName”(是您缺少 using 指令或程序集引用?)

    即使我的 _ViewImports.cshtml 文件中有正确的命名空间。所以我决定使用 Razor 页面的能力来支持注入已经注册为依赖注入的服务。例如,我需要将配置文件中的一些值注入到我的 _Layout.cshtml 文件中。所以我做了以下事情:

    1) 定义了一个IConfigurationHelperService接口:

    public interface IConfigurationHelperService
    {
        string GetApiUrl();
    }
    

    2) 在 ConfigurationHelperSerivce 类中定义了该接口的实现(该类本身使用依赖注入来获取常规配置类):

     public class ConfigurationHelperService : IConfigurationHelperService
     {
        public ConfigurationHelperService(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        private IConfiguration Configuration { get; }
    
        public string GetApiUrl()
        {
            return GetConfigurationValue(ApiUrl);
        }
    
        private string GetConfigurationValue(string key)
        {
            var value = Configuration[key];
            if (value.IsNullOrEmpty()) throw new KeyNotFoundException($"Configruation does not contain an instance of {key}");
            return value;
        }
    }
    

    3) 在 Startup.cs 中通过 ConfigureServices 注册注入服务:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IConfigurationHelperService, ConfigurationHelperService>();
        services.AddMvc();
    }
    

    4) 将正确的命名空间作为 using 语句添加到我的 _ViewImports.cshtml 文件中。

    5) 使用 @inject 关键字定义它以在 _Layout.cshtml 文件中使用。

    @inject IConfigurationHelperService ConfigHelper
    <!DOCTYPE html>
    <html>
    ...
    @ConfigHelper.GetApiUrl()
    ...
    </html>
    

    它对我来说非常有用,而且我可以在更简单的页面上看到它的更多用途,因为定义模型的工作量太大。

    【讨论】:

    • 我遇到了同样的问题,通过公开扩展类解决了它。
    【解决方案4】:

    对我而言,我认为我的 HTML 助手无法正常工作,直到我发现扩展方法现在位于 IHtmlHelper 而不是 HtmlHelper

    所以对于 .net 核心

    public static IHtmlContent CheckboxListFor<TModel>(this IHtmlHelper<TModel> html,
                Expression<Func<TModel, List<CheckboxListItem>>> expression) ...
    

    而不是 .net

    public static HtmlString CheckboxListFor<TModel>(this HtmlHelper<TModel> html,
                Expression<Func<TModel, List<CheckboxListItem>>> expression) ...
    

    编辑:我还将 .net 核心的返回类型更新为 IHtmlContent,因为使用 HtmlContentBuilder 之类的东西是编写 HTML 内容和返回返回IHtmlContent

    【讨论】:

    • 没有注意到我的错误中的区别,应该尝试过界面。谢谢!
    【解决方案5】:

    好吧,我想这个答案不会被注意到,但这是我使用服务注册想出的:

    我希望它对某人有所帮助。

    注册服务:

    services.AddTransient<IHtmlHelperFactory, HtmlHelperFactory>();
    

    使用服务:

    var helper = HttpContext.RequestServices.GetRequiredService<IHtmlHelperFactory>().Create();
    

    界面:

    public interface IHtmlHelperFactory
    {
        IHtmlHelper Create();
    }
    

    实施:

    public class HtmlHelperFactory : IHtmlHelperFactory
    {
        private readonly IHttpContextAccessor _contextAccessor;
    
        public class FakeView : IView
        {
            /// <inheritdoc />
            public Task RenderAsync(ViewContext context)
            {
                return Task.CompletedTask;
            }
    
            /// <inheritdoc />
            public string Path { get; } = "View";
        }
    
        public HtmlHelperFactory(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }
    
        /// <inheritdoc />
        public IHtmlHelper Create()
        {
            var modelMetadataProvider = _contextAccessor.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>();
            var tempDataProvider = _contextAccessor.HttpContext.RequestServices.GetRequiredService<ITempDataProvider>();
            var htmlHelper = _contextAccessor.HttpContext.RequestServices.GetRequiredService<IHtmlHelper>();
            var viewContext = new ViewContext(
                new ActionContext(_contextAccessor.HttpContext, _contextAccessor.HttpContext.GetRouteData(), new ControllerActionDescriptor()),
                new FakeView(),
                new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary()),
                new TempDataDictionary(_contextAccessor.HttpContext, tempDataProvider),
                TextWriter.Null,
                new HtmlHelperOptions()
            );
    
            ((IViewContextAware)htmlHelper).Contextualize(viewContext);
            return htmlHelper;
        }
    }
    

    【讨论】:

      【解决方案6】:

      这是一个使用 TagBuilders 的 .Net Core 2 示例

      using Microsoft.AspNetCore.Html;
      using Microsoft.AspNetCore.Mvc.Rendering;
      using System.IO;
      
      public static IHtmlContent HelloWorld(this IHtmlHelper html, string name)
      {
          var span = new TagBuilder("span");
          span.InnerHtml.Append("Hello, " + name + "!");
      
          var br = new TagBuilder("br") {TagRenderMode = TagRenderMode.SelfClosing};
      
          string result;
      
          using (var writer = new StringWriter())
          {
              span.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
              br.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
              result = writer.ToString();
          }
      
          return new HtmlString(result);
      }
      

      【讨论】:

      • 我错过了WriteTo 部分。谢谢(y)
      【解决方案7】:

      这是一个根据视图中的 Enum 值获取 Enum 名称的示例。枚举类型的自定义 HTML 帮助器

      public static IHtmlContent DisplayEnumFor(this IHtmlHelper htmlHelper, string value, Type enumType)
      {
          if (htmlHelper == null)
              throw new ArgumentNullException(nameof(htmlHelper));
      
          if (value == null)
              throw new ArgumentNullException(nameof(value));
      
          if (!enumType.IsEnum)
              throw new ArgumentException("Type must be an enumerated type");
      
          foreach (var item in Enum.GetValues(enumType))
              if (((int)item).ToString().Equals(value.Trim()))
                  return new HtmlString(item.ToString());
      
          return new HtmlString(value);
      }
      

      【讨论】:

        【解决方案8】:

        要创建自定义 HTML 助手,您需要创建一个静态类和静态方法。

        以下示例是用于提交按钮的自定义 HTML 帮助器。

        namespace TagHelpers.Helpers
        {
            public static class CustomHtmlHelpers
            {
                public static IHtmlContent SubmitButton(this IHtmlHelper htmlHelper, string value, string name )
                {
                    string str = "<input type='submit' value ='"+ value +"'name='"+ name +"' />";
                    return new HtmlString(str);
                }
            }
        }
        

        确保在下面添加 using 语句。

        using Microsoft.AspNetCore.Html;
        using Microsoft.AspNetCore.Mvc.Rendering;
        

        要在页面上的任何位置访问帮助程序,您需要将命名空间添加到 viewimports.cshtml 文件中

        @using TagHelpers.Helpers
        

        现在,您现在可以在要定义按钮的页面上使用它了。

        <div>
                @Html.SubmitButton("Login", "Command")
                @Html.SubmitButton("Cancel", "Command")
        </div>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-06
          • 1970-01-01
          相关资源
          最近更新 更多