This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add <head> and <body> Tag Helpers #5728
Comments
@jbagga please set up a mtg with me, @NTaylorMullen @DamianEdwards (required), and @davidfowl (optional) to figure this out. |
Here's a straw-man for us to start from that I just hacked together that works. The scenario at the end is the Application Insights SDK injecting the client-side analytics JavaScript without anything needing to be in [HtmlTargetElement("head")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class HeadTagHelper : TagHelper
{
private readonly IList<IHeadTagHelper> _processors;
public HeadTagHelper(IEnumerable<IHeadTagHelper> processors)
{
_processors = processors.OrderBy(p => p.Order).ToList();
}
public override void Init(TagHelperContext context)
{
foreach (var processor in _processors)
{
processor.Init(context);
}
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
foreach (var processor in _processors)
{
await processor.ProcessAsync(context, output);
}
}
}
[HtmlTargetElement("body")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class BodyTagHelper : TagHelper
{
private readonly IList<IBodyTagHelper> _processors;
public BodyTagHelper(IEnumerable<IBodyTagHelper> processors)
{
_processors = processors.OrderBy(p => p.Order).ToList();
}
public override void Init(TagHelperContext context)
{
foreach (var processor in _processors)
{
processor.Init(context);
}
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
foreach (var processor in _processors)
{
await processor.ProcessAsync(context, output);
}
}
}
public interface IHeadTagHelper
{
int Order { get; }
void Init(TagHelperContext context);
Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
}
public interface IBodyTagHelper
{
int Order { get; }
void Init(TagHelperContext context);
Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
}
public class AppInsightsHeadTagHelper : IHeadTagHelper
{
private readonly string _js;
public AppInsightsHeadTagHelper(JavaScriptSnippet appInsightsJs)
{
_js = appInsightsJs.FullScript;
}
public int Order => 1;
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.PostContent.AppendHtml("<script>console.log('This was injected!!');</script>");
output.PostContent.AppendHtml(_js);
return Task.CompletedTask;
}
}
public static class WebHostExtensions
{
public static IWebHostBuilder UseApplicationInsights2(this IWebHostBuilder builder) => builder
.UseApplicationInsights()
.ConfigureServices(services => services
.AddSingleton<IHeadTagHelper, AppInsightsHeadTagHelper>());
} |
Very nice. So given this code, which seems to be fine, what design questions do we actually have? |
We should discuss naming and enumerate some more scenarios to ensure this covers what we want. Also, what config, options, logging, etc. we might want. |
Idea to make this more generic: public interface ITagHelperComponent
{
bool AppliesTo(TagHelperContext context);
int Order { get; }
void Init(TagHelperContext context);
Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
}
[HtmlTargetElement("body")]
[HtmlTargetElement("head")]
public class BodyHeadTagHelper : TagHelperComponentTagHelper
{
}
public abstract class TagHelperComponentTagHelper : TagHelper
{
private readonly IList<ITagHelperComponent> _components;
public TagHelperComponentTagHelper(IEnumerable<ITagHelperComponent> components)
{
_components = components.OrderBy(p => p.Order).ToList();
}
public override void Init(TagHelperContext context)
{
foreach (var component in _components)
{
if (component.AppliesTo(context))
{
component.Init(context);
}
}
}
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
foreach (var component in _components)
{
if (component.AppliesTo(context))
{
await component.ProcessAsync(context, output);
}
}
}
}
public class AppInsightsHeadTagHelperComponent : ITagHelperComponent
{
private readonly string _js;
public AppInsightsHeadTagHelperComponent(JavaScriptSnippet appInsightsJs)
{
_js = appInsightsJs.FullScript;
}
public bool AppliesTo(TagHelperContext context) => string.Equals("head", context.TagName, StringComparison.OrdinalIgnoreCase);
public int Order => 1;
public void Init(TagHelperContext context)
{
}
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
output.PostContent.AppendHtml("<script>console.log('This was injected!!');</script>");
output.PostContent.AppendHtml(_js);
return Task.CompletedTask;
}
} |
This was referenced Mar 4, 2017
This was referenced Mar 8, 2017
jbagga
added a commit
to aspnet/Razor
that referenced
this issue
Mar 24, 2017
Addresses aspnet/Mvc#5728
jbagga
added a commit
to aspnet/Razor
that referenced
this issue
Mar 29, 2017
👏 |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
They need to allow components in DI to add stuff to be rendered in the
<head>
and/or<body>
elements. Maybe viaTagHelperInitializer
s? Need to consider support for ordering too.The text was updated successfully, but these errors were encountered: