Create Custom HTML Helper in ASP.Net Core

前端 未结 7 1226
南笙
南笙 2020-12-28 13:10

I want to create my own custom HTML Helper like the ones used in ASP.NET MVC, but I haven\'t been able to find how to implement them in the correct way.

I have found

相关标签:
7条回答
  • 2020-12-28 13:25

    Here is an example to get Enum name based on the Enum value in view. Custom HTML Helper for Enum Type

    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);
    }
    
    0 讨论(0)
  • 2020-12-28 13:31

    Here is an example for .Net Core 2 using TagBuilders

    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);
    }
    
    0 讨论(0)
  • 2020-12-28 13:32

    HTML Helpers look to be supported in ASP.NET Core and are awaiting documentation:

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

    [Edit:] Since answering, the above page no longer exists. I'd say HTML Helpers, while they work, are no longer "supported" in ASP.NET Core.

    Looking at the ASP.NET Core source they work fairly similarly to older versions of ASP.NET MVC:

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


    Example

    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 (second line is the important change):

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

    MyView.cshtml:

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

    Outputs:

    Hello World

    <strong>Hello World</strong>

    0 讨论(0)
  • 2020-12-28 13:41

    For me I thought my HTML helpers weren't working until I spotted that the extension method is now on IHtmlHelper not HtmlHelper.

    So for .net core:

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

    Instead of for .net:

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

    EDIT: I've also updated the return type for .net core to be IHtmlContent as using something like HtmlContentBuilder is a nicer way to compose HTML content and returning that returns IHtmlContent

    0 讨论(0)
  • 2020-12-28 13:41

    I was never able to get HtmlHelper extension methods to work, I always recieved:

    'IHtmlHelper' does not contain a definition for 'MethodName' and no extension method 'MethodName' accepting a first argument of type 'IHtmlHelper' could be found (are you missing a using directive or an assembly reference?)

    Even though I had the proper namespace in my _ViewImports.cshtml file. So I decided to use the ability of Razor pages to now support injecting services that have been registered for dependency injection. As an example I have the need to inject some values from my configuration file into my _Layout.cshtml file. So I did the following:

    1) Defined a IConfigurationHelperService interface:

    public interface IConfigurationHelperService
    {
        string GetApiUrl();
    }
    

    2) Defined an implementation of that interface in a ConfigurationHelperSerivce class (which itself is using dependency injection to get the regular configuration class):

     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) Registered the service for injection via ConfigureServices in Startup.cs:

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

    4) Added the proper namespace as a using statement into my _ViewImports.cshtml file.

    5) Used the @inject keyword to define it for use in the _Layout.cshtml file.

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

    It worked great for me, and I can see a lot more uses for this on simpler pages where defining models would be too much work.

    0 讨论(0)
  • 2020-12-28 13:42

    Well i guess this answer won't be noticed but here's what i came up with using service registrations:

    I hope it helps someone.

    Register the service:

    services.AddTransient<IHtmlHelperFactory, HtmlHelperFactory>();
    

    Use the service:

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

    Interface:

    public interface IHtmlHelperFactory
    {
        IHtmlHelper Create();
    }
    

    Implementation:

    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;
        }
    }
    
    0 讨论(0)
提交回复
热议问题