parent
04f74edd85
commit
e681c23d5c
|
|
@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Mvc.Razor;
|
|||
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.AspNetCore.Razor.Language;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
|
@ -187,6 +188,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
services.TryAddSingleton<ITagHelperActivator, DefaultTagHelperActivator>();
|
||||
services.TryAddSingleton<ITagHelperFactory, DefaultTagHelperFactory>();
|
||||
|
||||
// TagHelperComponents manager
|
||||
services.TryAddScoped<ITagHelperComponentManager, TagHelperComponentManager>();
|
||||
|
||||
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
|
||||
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// The default implementation of the <see cref="ITagHelperComponentManager"/>.
|
||||
/// </summary>
|
||||
public class TagHelperComponentManager : ITagHelperComponentManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="TagHelperComponentManager"/>.
|
||||
/// </summary>
|
||||
/// <param name="tagHelperComponents">The collection of <see cref="ITagHelperComponent"/>s.</param>
|
||||
public TagHelperComponentManager(IEnumerable<ITagHelperComponent> tagHelperComponents)
|
||||
{
|
||||
if (tagHelperComponents == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagHelperComponents));
|
||||
}
|
||||
|
||||
Components = new List<ITagHelperComponent>(tagHelperComponents);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ITagHelperComponent> Components { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -18,10 +17,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
/// <summary>
|
||||
/// Creates a new <see cref="BodyTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="components">The list of <see cref="ITagHelperComponent"/>.</param>
|
||||
/// <param name="manager">The <see cref="ITagHelperComponentManager"/> which contains the collection
|
||||
/// of <see cref="ITagHelperComponent"/>s.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public BodyTagHelper(IEnumerable<ITagHelperComponent> components, ILoggerFactory loggerFactory)
|
||||
: base(components, loggerFactory)
|
||||
public BodyTagHelper(ITagHelperComponentManager manager, ILoggerFactory loggerFactory)
|
||||
: base(manager, loggerFactory)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -18,10 +17,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
/// <summary>
|
||||
/// Creates a new <see cref="HeadTagHelper"/>.
|
||||
/// </summary>
|
||||
/// <param name="components">The list of <see cref="ITagHelperComponent"/>.</param>
|
||||
/// <param name="manager">The <see cref="ITagHelperComponentManager"/> which contains the collection
|
||||
/// of <see cref="ITagHelperComponent"/>s.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public HeadTagHelper(IEnumerable<ITagHelperComponent> components, ILoggerFactory loggerFactory)
|
||||
: base(components, loggerFactory)
|
||||
public HeadTagHelper(ITagHelperComponentManager manager, ILoggerFactory loggerFactory)
|
||||
: base(manager, loggerFactory)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of this interface provides the collection of <see cref="ITagHelperComponent"/>s
|
||||
/// that will be used by <see cref="TagHelperComponentTagHelper"/>s.
|
||||
/// </summary>
|
||||
public interface ITagHelperComponentManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the collection of <see cref="ITagHelperComponent"/>s that will be used by
|
||||
/// <see cref="TagHelperComponentTagHelper"/>s.
|
||||
/// </summary>
|
||||
ICollection<ITagHelperComponent> Components { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,10 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes and processes the <see cref="ITagHelperComponent"/>s added to the
|
||||
/// <see cref="ITagHelperComponentManager.Components"/> in the specified order.
|
||||
/// </summary>
|
||||
public abstract class TagHelperComponentTagHelper : TagHelper
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
|
@ -18,16 +22,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
private IEnumerable<ITagHelperComponent> _components;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="TagHelperComponentTagHelper"/>.
|
||||
/// Creates a new <see cref="TagHelperComponentTagHelper"/> and orders the
|
||||
/// the collection of <see cref="ITagHelperComponent"/>s in <see cref="ITagHelperComponentManager.Components"/>.
|
||||
/// </summary>
|
||||
/// <param name="components">The list of <see cref="ITagHelperComponent"/>.</param>
|
||||
/// <param name="manager">The <see cref="ITagHelperComponentManager"/> which contains the collection
|
||||
/// of <see cref="ITagHelperComponent"/>s.</param>
|
||||
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||
public TagHelperComponentTagHelper(IEnumerable<ITagHelperComponent> components,
|
||||
/// <remarks>The <see cref="ITagHelperComponentManager.Components"/> are ordered after the
|
||||
/// creation of the <see cref="ITagHelperComponentManager"/> to position the <see cref="ITagHelperComponent"/>s
|
||||
/// added from controllers and views correctly.</remarks>
|
||||
public TagHelperComponentTagHelper(ITagHelperComponentManager manager,
|
||||
ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (components == null)
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(components));
|
||||
throw new ArgumentNullException(nameof(manager));
|
||||
}
|
||||
|
||||
if (loggerFactory == null)
|
||||
|
|
@ -35,14 +44,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
throw new ArgumentNullException(nameof(loggerFactory));
|
||||
}
|
||||
|
||||
_components = components;
|
||||
_components = manager.Components.OrderBy(p => p.Order).ToArray();
|
||||
_logger = loggerFactory.CreateLogger(GetType());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Init(TagHelperContext context)
|
||||
{
|
||||
_components = _components.OrderBy(p => p.Order);
|
||||
foreach (var component in _components)
|
||||
{
|
||||
component.Init(context);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,30 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
#if GENERATE_BASELINES
|
||||
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
|
||||
#else
|
||||
Assert.Equal(expectedContent, responseContent, ignoreLineEndingDifferences: true);
|
||||
#endif
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddTestTagHelperComponent_FromController()
|
||||
{
|
||||
// Arrange
|
||||
var url = "http://localhost/AddTagHelperComponent/AddComponent";
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
var outputFile = "compiler/resources/RazorWebSite.AddTagHelperComponent.AddComponent.html";
|
||||
var expectedContent =
|
||||
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
|
||||
|
||||
// Act
|
||||
var response = await Client.SendAsync(request);
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
#if GENERATE_BASELINES
|
||||
ResourceFile.UpdateFile(_resourcesAssembly, outputFile, expectedContent, responseContent);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<head inject>
|
||||
Hello from Head Tag Helper Component
|
||||
<script>'This was injected!!'</script></head>
|
||||
<body inject>
|
||||
Hello from Body Tag Helper Component
|
||||
Processed TagHelperComponent added from controller.<script>'This was injected!!'</script>Processed TagHelperComponent added from view.</body>
|
||||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
|
@ -27,7 +28,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
uniqueId: "test");
|
||||
|
||||
var incrementer = 0;
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new []
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new []
|
||||
{
|
||||
new CallbackTagHelperComponent(
|
||||
order: 2,
|
||||
|
|
@ -53,7 +54,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
incrementer++;
|
||||
},
|
||||
processAsyncCallback: null),
|
||||
}, NullLoggerFactory.Instance);
|
||||
});
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, NullLoggerFactory.Instance);
|
||||
|
||||
// Act
|
||||
testTagHelperComponentTagHelper.Init(tagHelperContext);
|
||||
|
|
@ -80,7 +83,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
new DefaultTagHelperContent()));
|
||||
|
||||
var incrementer = 0;
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new []
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new []
|
||||
{
|
||||
new CallbackTagHelperComponent(
|
||||
order: 2,
|
||||
|
|
@ -106,7 +109,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
Assert.Equal(0, incrementer);
|
||||
incrementer++;
|
||||
}),
|
||||
}, NullLoggerFactory.Instance);
|
||||
});
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, NullLoggerFactory.Instance);
|
||||
|
||||
// Act
|
||||
testTagHelperComponentTagHelper.Init(tagHelperContext);
|
||||
|
|
@ -133,10 +138,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
|
||||
new DefaultTagHelperContent()));
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new []
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new[]
|
||||
{
|
||||
new TestTagHelperComponent()
|
||||
}, NullLoggerFactory.Instance);
|
||||
});
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, NullLoggerFactory.Instance);
|
||||
|
||||
// Act
|
||||
testTagHelperComponentTagHelper.Init(tagHelperContext);
|
||||
|
|
@ -162,16 +169,51 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
|
||||
new DefaultTagHelperContent()));
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new []
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new []
|
||||
{
|
||||
new TestTagHelperComponent()
|
||||
}, NullLoggerFactory.Instance);
|
||||
});
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, NullLoggerFactory.Instance);
|
||||
|
||||
// Act
|
||||
await testTagHelperComponentTagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Processed", output.PostContent.GetContent());
|
||||
Assert.Equal("Processed1", output.PostContent.GetContent());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_InvokesTagHelperComponentProcessAsync_WithAddedTagHelperComponents()
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperContext = new TagHelperContext(
|
||||
"head",
|
||||
allAttributes: new TagHelperAttributeList(
|
||||
Enumerable.Empty<TagHelperAttribute>()),
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: "test");
|
||||
|
||||
var output = new TagHelperOutput(
|
||||
"head",
|
||||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
|
||||
new DefaultTagHelperContent()));
|
||||
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new []
|
||||
{
|
||||
new TestTagHelperComponent()
|
||||
});
|
||||
|
||||
testTagHelperComponentManager.Components.Add(new TestAddTagHelperComponent(0));
|
||||
testTagHelperComponentManager.Components.Add(new TestAddTagHelperComponent(2));
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, NullLoggerFactory.Instance);
|
||||
|
||||
// Act
|
||||
await testTagHelperComponentTagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Processed0Processed1Processed2", output.PostContent.GetContent());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -193,10 +235,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
|
||||
new DefaultTagHelperContent()));
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new []
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new []
|
||||
{
|
||||
new TestTagHelperComponent()
|
||||
}, loggerFactory);
|
||||
});
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, loggerFactory);
|
||||
|
||||
// Act
|
||||
testTagHelperComponentTagHelper.Init(tagHelperContext);
|
||||
|
|
@ -224,10 +268,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(
|
||||
new DefaultTagHelperContent()));
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new []
|
||||
var testTagHelperComponentManager = new TagHelperComponentManager(new []
|
||||
{
|
||||
new TestTagHelperComponent()
|
||||
}, loggerFactory);
|
||||
});
|
||||
|
||||
var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(testTagHelperComponentManager, loggerFactory);
|
||||
|
||||
// Act
|
||||
await testTagHelperComponentTagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
|
@ -239,9 +285,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
private class TestTagHelperComponentTagHelper : TagHelperComponentTagHelper
|
||||
{
|
||||
public TestTagHelperComponentTagHelper(
|
||||
IEnumerable<ITagHelperComponent> components,
|
||||
ITagHelperComponentManager manager,
|
||||
ILoggerFactory loggerFactory)
|
||||
: base(components, loggerFactory)
|
||||
: base(manager, loggerFactory)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -284,7 +330,29 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
|||
|
||||
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.PostContent.AppendHtml("Processed");
|
||||
output.PostContent.AppendHtml("Processed1");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestAddTagHelperComponent : ITagHelperComponent
|
||||
{
|
||||
private int _order;
|
||||
|
||||
public TestAddTagHelperComponent(int order)
|
||||
{
|
||||
_order = order;
|
||||
}
|
||||
|
||||
public int Order => _order;
|
||||
|
||||
public void Init(TagHelperContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
output.PostContent.AppendHtml("Processed" + Order);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
|
||||
|
||||
namespace RazorWebSite.Controllers
|
||||
{
|
||||
public class AddTagHelperComponentController : Controller
|
||||
{
|
||||
private readonly ITagHelperComponentManager _tagHelperComponentManager;
|
||||
|
||||
public AddTagHelperComponentController(ITagHelperComponentManager tagHelperComponentManager)
|
||||
{
|
||||
_tagHelperComponentManager = tagHelperComponentManager;
|
||||
}
|
||||
|
||||
public IActionResult AddComponent()
|
||||
{
|
||||
_tagHelperComponentManager.Components.Add(new TestBodyTagHelperComponent(0, "Processed TagHelperComponent added from controller."));
|
||||
return View("AddComponent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,15 +7,33 @@ using Microsoft.AspNetCore.Razor.TagHelpers;
|
|||
|
||||
namespace RazorWebSite
|
||||
{
|
||||
public class TestBodyTagHelperComponent : TagHelperComponent
|
||||
public class TestBodyTagHelperComponent : ITagHelperComponent
|
||||
{
|
||||
public override int Order => 1;
|
||||
private int _order;
|
||||
private string _html;
|
||||
|
||||
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
public TestBodyTagHelperComponent() : this(1, "<script>'This was injected!!'</script>")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TestBodyTagHelperComponent(int order, string html)
|
||||
{
|
||||
_order = order;
|
||||
_html = html;
|
||||
}
|
||||
|
||||
public int Order => _order;
|
||||
|
||||
public void Init(TagHelperContext context)
|
||||
{
|
||||
}
|
||||
|
||||
public Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
|
||||
{
|
||||
if (string.Equals(context.TagName, "body", StringComparison.Ordinal) && output.Attributes.ContainsName("inject"))
|
||||
{
|
||||
output.PostContent.AppendHtml("<script>'This was injected!!'</script>");
|
||||
output.PostContent.AppendHtml(_html);
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
@inject Microsoft.AspNetCore.Mvc.Razor.TagHelpers.ITagHelperComponentManager manager
|
||||
<head inject>
|
||||
Hello from Head Tag Helper Component
|
||||
</head>
|
||||
@{
|
||||
manager.Components.Add(new TestBodyTagHelperComponent(2, "Processed TagHelperComponent added from view."));
|
||||
}
|
||||
<body inject>
|
||||
Hello from Body Tag Helper Component
|
||||
</body>
|
||||
Loading…
Reference in New Issue