Создание пользовательского HTML-помощника в ASP.Net Core

Я хочу создать свой собственный HTML-помощник, как в MVC, но я не нахожу, как сделать правильный путь.

Я нашел, как создавать пользовательские помощники тегов, но не помощники HTML.

Спасибо за ваше время!

Ответ 1

Для меня я думал, что мои помощники HTML не работают, пока я не заметил, что метод расширения теперь находится на IHtmlHelper not HtmlHelper.

Итак, для .net core:

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) ...

EDIT: Я также обновил тип возвращаемого значения для ядра .net как IHtmlContent, поскольку использование чего-то типа HtmlContentBuilder - это лучший способ составить HTML-контент и возвращающий, который возвращает IHtmlContent

Ответ 2

HTML-помощники ищут поддержку в ядре ASP.NET и ждут документации:

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

Глядя на источник ASP.NET Core, они работают довольно аналогично старым версиям ASP.NET MVC:

https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNetCore.Mvc.ViewFeatures/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>

Выходы:

Hello World

<strong> Hello World </strong>

Ответ 3

Это было хорошо объяснено Дэнни ван дер Крааном в своем блоге

С помощью привязки TagHelper это будет выглядеть так:

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

PS: Обратите внимание, что asp - это просто соглашение, но об этом позже.

Результат, отображаемый в браузере, одинаковый для обоих:

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

PS: Если маршрут по умолчанию не изменен.

Для получения дополнительной информации о TagHelpers

Ответ 4

Мне никогда не удавалось использовать методы расширения HtmlHelper, я всегда получал:

"IHtmlHelper" не содержит определения для " Имя метода" и не может быть найден метод расширения " Имя метода", принимающий первый аргумент типа "IHtmlHelper" ( у вас отсутствует директива 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) Зарегистрировал сервис для инъекций через ConfigureServices в Startup.cs:

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

4) Добавлено собственное пространство имен в качестве используемого оператора в файл _ViewImports.cshtml.

5) Используется ключевое слово @inject, чтобы определить его для использования в файле _Layout.cshtml.

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

Это отлично поработало для меня, и я вижу гораздо больше возможностей для этого на более простых страницах, где определение моделей будет слишком большим.

Ответ 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

Вот пример для.Net Core 2 с помощью 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);
}