可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 how to create custom Tag Helpers but not HTML Helpers. How do I create my own custom HTML Helpers?
回答1:
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
回答2:
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>
回答3:
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.
回答4:
This has been well explained by Danny van der Kraan in his blog post here. The answer below is an extract from this post:
ASP.NET Core 1.0 [MVC 6]
comes with a new exciting feature called TagHelpers
. In ASP.Net Core 1.0
there is no concept of HTML Helper like in MVC.
What are TagHelpers?
TagHelpers
can be seen as the evolution of HTML helpers which were introduced with the launch of the first MVC
framework. To provide context you have to imagine that with classic ASP the only way you could automate the generation of HTML is via custom subroutines. After that ASP.NET came with server controls, with view states as biggest plus, to simulate the look and feel of desktop applications and help with the transition for desktop developers. But we all know what happens when we try to jam squares in to round holes. We had to face the fact that web development is nothing like desktop development. To get in line with proper web development the ASP.NET MVC
framework was launched with HTML helpers to automate the HTML output. But HTML helpers never really gelled, especially not with front end developers and designers. One of the main pet peeves was that it made you switch a lot from angle brackets (HTML, CSS)
to C# (Razor syntax)
during work on views, which made the experience unnecessarily uncomfortable. [MVC 6]
wants to address this and some smaller issues by introducing TagHelpers
. Example
HTML helper:
@Html.ActionLink(”Home”, ”Index”, ”Home”)
With the anchor TagHelper this would look like:
<a asp-action="Index" asp-controller="Home">Home</a>
PS: Please note that asp- is just a convention, but more on that later.
The output rendered in the browser is the same for both:
<a href="/">Home</a>
PS: Provided the default route has not been altered.
For more information about TagHelpers
click here
回答5:
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;
}
}
回答6:
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);
}