In ASP.NET Core is it possible to detect whether a tag helper is rendered with a parent element?
The reason I ask is that I have a script tag helper which caches the HTML it would normally render and instead I use middleware to render the HTML before the closing body tag. However if the tag helper is called within a partial view then I'd like to simply render it in place.
My first thoughts was to add a body tag helper and then add a variable to the request cache, which I could detect within my script tag helper. However I found that since the body tag helper was within my layout page, it was rendered after my view (which executes the script tag helper).
Another solution I thought was to store a variable within the action, but I don't like this as I have to remember to do this every time I return a partial view.
I'd appreciate any help.
Edit: Here's some code for reference.
ScriptTagHelper:
public class ScriptTagHelper : TagHelper {
private readonly IHtmlManager _htmlManager;
public ScriptTagHelper(IHtmlManager htmlManager) {
_htmlManager = htmlManager;
}
public string? At { get; set; }
[HtmlAttributeNotBound, ViewContext]
public ViewContext ViewContext { get; set; } = default!;
public override void Process(TagHelperContext context, TagHelperOutput output) {
if (!string.IsNullOrEmpty(At)) {
output.SuppressOutput();
var builder = new TagBuilder("script") {
TagRenderMode = TagRenderMode.Normal
};
foreach (var attribute in output.Attributes) {
builder.Attributes.Add(attribute.Name, attribute.Value.ToString());
}
_htmlManager.RegisterHtml(At, builder);
}
}
}
Here's my middleware:
public class RenderHtmlMiddleware {
private readonly RequestDelegate _next;
public RenderHtmlMiddleware(RequestDelegate next) {
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext, IHtmlManager htmlManager) {
var originBody = httpContext.Response.Body;
using var body = new MemoryStream();
httpContext.Response.Body = body;
try {
await _next(httpContext);
} finally {
httpContext.Response.Body = originBody;
}
if (body.Length > 0) {
var content = Encoding.UTF8.GetString(body.ToArray());
foreach (var position in Enum.GetValues<HtmlPosition>()) {
var html = await htmlManager.GetHtmlAsync(position);
var innerHtml = string.Join("", html.Select(h => h.ToHtmlString()));
... Code removed for brevity which handles different positions
content = content.Replace("</body>", string.Concat(innerHtml, Environment.NewLine, "</body>"));
}
httpContext.Response.ContentLength = Encoding.UTF8.GetByteCount(content);
await httpContext.Response.WriteAsync(content);
}
}
}
Now within my view/partial view I can simply say:
<script at="@HtmlPosition.BodyPostContent" src="foo"></script>
If you just want to check if it was rendered in a partialview:
you may add a property:
You could access HttpContext/current view name with ViewContext
a minimal example:
In Home View:
In Partial View:
Result:
only
<label>partial</label>was renderedUpdate: A possible solution for template:
In View:
In partial:
Template:
Even if taghelper was call in template,Only that in partial view was rendered: