From eda5028cf4c049985db3ed0124bd2d9f067bb956 Mon Sep 17 00:00:00 2001 From: Jass Bagga Date: Wed, 29 Mar 2017 11:29:24 -0700 Subject: [PATCH] Add TagHelperComponentTagHelper Addresses #5728 --- .../MvcRazorTemplateEngine.cs | 2 + .../Internal/MvcRazorLoggerExtensions.cs | 23 ++ .../TagHelpers/BodyTagHelper.cs | 26 ++ .../TagHelpers/HeadTagHelper.cs | 26 ++ .../TagHelpers/TagHelperComponentTagHelper.cs | 69 +++++ .../TagHelperComponentTagHelperTest.cs | 71 +++++ .../RazorWebSite.TagHelperComponent.Body.html | 3 + .../RazorWebSite.TagHelperComponent.Head.html | 3 + .../MvcRazorTemplateEngineTest.cs | 10 +- .../TestFiles/Output/DesignTime/Basic.cs | 8 + .../Output/DesignTime/Basic.mappings.txt | 4 +- .../TestFiles/Output/DesignTime/Inject.cs | 8 + .../Output/DesignTime/Inject.mappings.txt | 4 +- .../Output/DesignTime/InjectWithModel.cs | 8 + .../DesignTime/InjectWithModel.mappings.txt | 10 +- .../Output/DesignTime/InjectWithSemicolon.cs | 8 + .../InjectWithSemicolon.mappings.txt | 18 +- .../TestFiles/Output/DesignTime/Model.cs | 8 + .../Output/DesignTime/Model.mappings.txt | 2 +- .../DesignTime/ModelExpressionTagHelper.cs | 8 + .../ModelExpressionTagHelper.mappings.txt | 16 +- .../Output/DesignTime/MultipleModels.cs | 8 + .../DesignTime/MultipleModels.mappings.txt | 4 +- .../Output/DesignTime/_ViewImports.cs | 8 + .../DesignTime/_ViewImports.mappings.txt | 4 +- .../TagHelperComponentTagHelperTest.cs | 292 ++++++++++++++++++ .../TagHelperComponentController.cs | 21 ++ .../Services/TestBodyTagHelperComponent.cs | 24 ++ .../Services/TestHeadTagHelperComponent.cs | 24 ++ test/WebSites/RazorWebSite/Startup.cs | 4 + .../Views/TagHelperComponent/Body.cshtml | 3 + .../Views/TagHelperComponent/Head.cshtml | 3 + 32 files changed, 696 insertions(+), 34 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/BodyTagHelper.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/HeadTagHelper.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/TagHelperComponentTagHelper.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelperComponentTagHelperTest.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Body.html create mode 100644 test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Head.html create mode 100644 test/Microsoft.AspNetCore.Mvc.Razor.Test/TagHelpers/TagHelperComponentTagHelperTest.cs create mode 100644 test/WebSites/RazorWebSite/Controllers/TagHelperComponentController.cs create mode 100644 test/WebSites/RazorWebSite/Services/TestBodyTagHelperComponent.cs create mode 100644 test/WebSites/RazorWebSite/Services/TestHeadTagHelperComponent.cs create mode 100644 test/WebSites/RazorWebSite/Views/TagHelperComponent/Body.cshtml create mode 100644 test/WebSites/RazorWebSite/Views/TagHelperComponent/Head.cshtml diff --git a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorTemplateEngine.cs b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorTemplateEngine.cs index c20dedef45..89bec3a6bb 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorTemplateEngine.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor.Host/MvcRazorTemplateEngine.cs @@ -52,6 +52,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.IUrlHelper Url"); writer.WriteLine("@inject global::Microsoft.AspNetCore.Mvc.ViewFeatures.IModelExpressionProvider ModelExpressionProvider"); writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor"); + writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"); + writer.WriteLine("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"); writer.Flush(); stream.Position = 0; diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/MvcRazorLoggerExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/MvcRazorLoggerExtensions.cs index 8d5dc6a1dd..55597fcf78 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/MvcRazorLoggerExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/MvcRazorLoggerExtensions.cs @@ -21,6 +21,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal private static readonly Action _viewLookupCacheHit; private static readonly Action _precompiledViewFound; + private static readonly Action _tagHelperComponentInitialized; + private static readonly Action _tagHelperComponentProcessed; + static MvcRazorLoggerExtensions() { _razorFileToCodeCompilationStart = LoggerMessage.Define( @@ -57,6 +60,16 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal LogLevel.Debug, 2, "Compilation of the generated code for the Razor file at '{FilePath}' completed in {ElapsedMilliseconds}ms."); + + _tagHelperComponentInitialized = LoggerMessage.Define( + LogLevel.Debug, + 2, + "Tag helper component '{ComponentName}' initialized."); + + _tagHelperComponentProcessed = LoggerMessage.Define( + LogLevel.Debug, + 3, + "Tag helper component '{ComponentName}' processed."); } public static void RazorFileToCodeCompilationStart(this ILogger logger, string filePath) @@ -95,6 +108,16 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal _generatedCodeToAssemblyCompilationStart(logger, filePath, null); } + public static void TagHelperComponentInitialized(this ILogger logger, string componentName) + { + _tagHelperComponentInitialized(logger, componentName, null); + } + + public static void TagHelperComponentProcessed(this ILogger logger, string componentName) + { + _tagHelperComponentProcessed(logger, componentName, null); + } + public static void GeneratedCodeToAssemblyCompilationEnd(this ILogger logger, string filePath, long startTimestamp) { // Don't log if logging wasn't enabled at start of request as time will be wildly wrong. diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/BodyTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/BodyTagHelper.cs new file mode 100644 index 0000000000..9c263acd91 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/BodyTagHelper.cs @@ -0,0 +1,26 @@ +// 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; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers +{ + /// + /// A targeting the <body> HTML element. + /// + [HtmlTargetElement("body")] + public class BodyTagHelper : TagHelperComponentTagHelper + { + /// + /// Creates a new . + /// + /// The list of . + /// The . + public BodyTagHelper(IEnumerable components, ILoggerFactory loggerFactory) + : base(components, loggerFactory) + { + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/HeadTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/HeadTagHelper.cs new file mode 100644 index 0000000000..488d3192f8 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/HeadTagHelper.cs @@ -0,0 +1,26 @@ +// 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; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers +{ + /// + /// A targeting the <head> HTML element. + /// + [HtmlTargetElement("head")] + public class HeadTagHelper : TagHelperComponentTagHelper + { + /// + /// Creates a new . + /// + /// The list of . + /// The . + public HeadTagHelper(IEnumerable components, ILoggerFactory loggerFactory) + : base(components, loggerFactory) + { + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/TagHelperComponentTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/TagHelperComponentTagHelper.cs new file mode 100644 index 0000000000..d5205564fb --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Razor/TagHelpers/TagHelperComponentTagHelper.cs @@ -0,0 +1,69 @@ +// 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 System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc.Razor.Internal; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers +{ + public abstract class TagHelperComponentTagHelper : TagHelper + { + private readonly ILogger _logger; + + private IEnumerable _components; + + /// + /// Creates a new . + /// + /// The list of . + /// The . + public TagHelperComponentTagHelper(IEnumerable components, + ILoggerFactory loggerFactory) + { + if (components == null) + { + throw new ArgumentNullException(nameof(components)); + } + + if (loggerFactory == null) + { + throw new ArgumentNullException(nameof(loggerFactory)); + } + + _components = components; + _logger = loggerFactory.CreateLogger(GetType()); + } + + /// + public override void Init(TagHelperContext context) + { + _components = _components.OrderBy(p => p.Order); + foreach (var component in _components) + { + component.Init(context); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.TagHelperComponentInitialized(component.GetType().FullName); + } + } + } + + /// + public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + foreach (var component in _components) + { + await component.ProcessAsync(context, output); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.TagHelperComponentProcessed(component.GetType().FullName); + } + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelperComponentTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelperComponentTagHelperTest.cs new file mode 100644 index 0000000000..3376c410ea --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/TagHelperComponentTagHelperTest.cs @@ -0,0 +1,71 @@ +// 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.Net; +using System.Net.Http; +using System.Reflection; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.FunctionalTests +{ + public class TagHelperComponentTagHelperTest : IClassFixture> + { + private static readonly Assembly _resourcesAssembly = typeof(TagHelperComponentTagHelperTest).GetTypeInfo().Assembly; + + public TagHelperComponentTagHelperTest(MvcTestFixture fixture) + { + Client = fixture.Client; + } + + public HttpClient Client { get; } + + [Fact] + public async Task InjectsTestHeadTagHelperComponent() + { + // Arrange + var url = "http://localhost/TagHelperComponent/GetHead"; + var request = new HttpRequestMessage(HttpMethod.Get, url); + var outputFile = "compiler/resources/RazorWebSite.TagHelperComponent.Head.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 + Assert.Equal(expectedContent, responseContent, ignoreLineEndingDifferences: true); +#endif + } + + [Fact] + public async Task InjectsTestBodyTagHelperComponent() + { + // Arrange + var url = "http://localhost/TagHelperComponent/GetBody"; + var request = new HttpRequestMessage(HttpMethod.Get, url); + var outputFile = "compiler/resources/RazorWebSite.TagHelperComponent.Body.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 + Assert.Equal(expectedContent, responseContent, ignoreLineEndingDifferences: true); +#endif + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Body.html b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Body.html new file mode 100644 index 0000000000..af76bea0cd --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Body.html @@ -0,0 +1,3 @@ + +Hello from Body Tag Helper Component + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Head.html b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Head.html new file mode 100644 index 0000000000..f4ecb47f0a --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/compiler/resources/RazorWebSite.TagHelperComponent.Head.html @@ -0,0 +1,3 @@ + +Hello from Head Tag Helper Component + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorTemplateEngineTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorTemplateEngineTest.cs index b55ef321a6..4bd5f3b78d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorTemplateEngineTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/MvcRazorTemplateEngineTest.cs @@ -81,9 +81,13 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Host var importContent = GetContent(imports) .Split(new[] { Environment.NewLine }, StringSplitOptions.None) .Where(line => line.StartsWith("@addTagHelper")); - var addTagHelper = Assert.Single(importContent); - Assert.Equal("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor", - addTagHelper); + + Assert.Contains("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor", + importContent); + Assert.Contains("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor", + importContent); + Assert.Contains("@addTagHelper Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor", + importContent); } [Fact] diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.cs index 7f731d1143..fa37322d97 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.cs @@ -74,6 +74,14 @@ System.Object ModelExpressionProvider = null; ))(); ((System.Action)(() => { System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResolutionTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; } ))(); } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.mappings.txt index 7d92c1a458..395437131c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Basic.mappings.txt @@ -1,10 +1,10 @@ Source Location: (13:0,13 [4] TestFiles/Input/Basic.cshtml) |logo| -Generated Location: (2329:85,13 [4] ) +Generated Location: (2691:93,13 [4] ) |logo| Source Location: (43:2,5 [21] TestFiles/Input/Basic.cshtml) |Html.Input("SomeKey")| -Generated Location: (2413:90,6 [21] ) +Generated Location: (2775:98,6 [21] ) |Html.Input("SomeKey")| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.cs index b1eaddccf2..944511195e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.cs @@ -82,6 +82,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { MyApp __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.mappings.txt index b70d124e04..58fbcf5188 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Inject.mappings.txt @@ -1,10 +1,10 @@ Source Location: (28:1,8 [5] TestFiles/Input/Inject.cshtml) |MyApp| -Generated Location: (2174:84,0 [5] ) +Generated Location: (2536:92,0 [5] ) |MyApp| Source Location: (34:1,14 [14] TestFiles/Input/Inject.cshtml) |MyPropertyName| -Generated Location: (2276:88,14 [14] ) +Generated Location: (2638:96,14 [14] ) |MyPropertyName| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.cs index 5c6b1cc223..cd16d5ca90 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.cs @@ -77,6 +77,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { MyModel __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.mappings.txt index afb241e019..27ff0c5d43 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithModel.mappings.txt @@ -1,25 +1,25 @@ Source Location: (7:0,7 [7] TestFiles/Input/InjectWithModel.cshtml) |MyModel| -Generated Location: (2091:79,0 [7] ) +Generated Location: (2453:87,0 [7] ) |MyModel| Source Location: (24:1,8 [5] TestFiles/Input/InjectWithModel.cshtml) |MyApp| -Generated Location: (2181:83,0 [5] ) +Generated Location: (2543:91,0 [5] ) |MyApp| Source Location: (30:1,14 [14] TestFiles/Input/InjectWithModel.cshtml) |MyPropertyName| -Generated Location: (2283:87,14 [14] ) +Generated Location: (2645:95,14 [14] ) |MyPropertyName| Source Location: (54:2,8 [17] TestFiles/Input/InjectWithModel.cshtml) |MyService| -Generated Location: (2367:91,0 [17] ) +Generated Location: (2729:99,0 [17] ) |MyService| Source Location: (72:2,26 [4] TestFiles/Input/InjectWithModel.cshtml) |Html| -Generated Location: (2481:95,14 [4] ) +Generated Location: (2843:103,14 [4] ) |Html| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.cs index e29dda4728..5f95c72be4 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.cs @@ -77,6 +77,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { MyModel __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.mappings.txt index 5a97d2ea5e..8663eb24b0 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/InjectWithSemicolon.mappings.txt @@ -1,45 +1,45 @@ Source Location: (7:0,7 [7] TestFiles/Input/InjectWithSemicolon.cshtml) |MyModel| -Generated Location: (2095:79,0 [7] ) +Generated Location: (2457:87,0 [7] ) |MyModel| Source Location: (24:1,8 [5] TestFiles/Input/InjectWithSemicolon.cshtml) |MyApp| -Generated Location: (2185:83,0 [5] ) +Generated Location: (2547:91,0 [5] ) |MyApp| Source Location: (30:1,14 [14] TestFiles/Input/InjectWithSemicolon.cshtml) |MyPropertyName| -Generated Location: (2287:87,14 [14] ) +Generated Location: (2649:95,14 [14] ) |MyPropertyName| Source Location: (58:2,8 [17] TestFiles/Input/InjectWithSemicolon.cshtml) |MyService| -Generated Location: (2371:91,0 [17] ) +Generated Location: (2733:99,0 [17] ) |MyService| Source Location: (76:2,26 [4] TestFiles/Input/InjectWithSemicolon.cshtml) |Html| -Generated Location: (2485:95,14 [4] ) +Generated Location: (2847:103,14 [4] ) |Html| Source Location: (93:3,8 [5] TestFiles/Input/InjectWithSemicolon.cshtml) |MyApp| -Generated Location: (2559:99,0 [5] ) +Generated Location: (2921:107,0 [5] ) |MyApp| Source Location: (99:3,14 [15] TestFiles/Input/InjectWithSemicolon.cshtml) |MyPropertyName2| -Generated Location: (2661:103,14 [15] ) +Generated Location: (3023:111,14 [15] ) |MyPropertyName2| Source Location: (129:4,8 [17] TestFiles/Input/InjectWithSemicolon.cshtml) |MyService| -Generated Location: (2746:107,0 [17] ) +Generated Location: (3108:115,0 [17] ) |MyService| Source Location: (147:4,26 [5] TestFiles/Input/InjectWithSemicolon.cshtml) |Html2| -Generated Location: (2860:111,14 [5] ) +Generated Location: (3222:119,14 [5] ) |Html2| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.cs index cc4902e48e..265c7288ab 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.cs @@ -77,6 +77,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { System.Collections.IEnumerable __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.mappings.txt index dec6abb9bd..095b2cb70b 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/Model.mappings.txt @@ -1,5 +1,5 @@ Source Location: (7:0,7 [30] TestFiles/Input/Model.cshtml) |System.Collections.IEnumerable| -Generated Location: (2104:79,0 [30] ) +Generated Location: (2466:87,0 [30] ) |System.Collections.IEnumerable| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.cs index 3a46d431fb..b4974b77be 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.cs @@ -77,6 +77,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { DateTime __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.mappings.txt index 9d6cf74fb2..98f9ca0e3d 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/ModelExpressionTagHelper.mappings.txt @@ -1,40 +1,40 @@ Source Location: (7:0,7 [8] TestFiles/Input/ModelExpressionTagHelper.cshtml) |DateTime| -Generated Location: (2101:79,0 [8] ) +Generated Location: (2463:87,0 [8] ) |DateTime| Source Location: (33:2,14 [91] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Microsoft.AspNetCore.Mvc.Razor.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Host.Test| -Generated Location: (2222:83,30 [91] ) +Generated Location: (2584:91,30 [91] ) |Microsoft.AspNetCore.Mvc.Razor.InputTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Host.Test| Source Location: (140:3,14 [102] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Microsoft.AspNetCore.Mvc.Razor.DictionaryPrefixTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Host.Test| -Generated Location: (2407:87,30 [102] ) +Generated Location: (2769:95,30 [102] ) |Microsoft.AspNetCore.Mvc.Razor.DictionaryPrefixTestTagHelper, Microsoft.AspNetCore.Mvc.Razor.Host.Test| Source Location: (263:5,17 [3] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Now| -Generated Location: (3397:100,133 [3] ) +Generated Location: (3759:108,133 [3] ) |Now| Source Location: (290:6,18 [5] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Model| -Generated Location: (3764:106,125 [5] ) +Generated Location: (4126:114,125 [5] ) |Model| Source Location: (322:8,19 [5] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Model| -Generated Location: (4183:112,153 [5] ) +Generated Location: (4545:120,153 [5] ) |Model| Source Location: (357:9,19 [4] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Hour| -Generated Location: (4611:118,161 [4] ) +Generated Location: (4973:126,161 [4] ) |Hour| Source Location: (378:9,40 [6] TestFiles/Input/ModelExpressionTagHelper.cshtml) |Minute| -Generated Location: (4873:123,163 [6] ) +Generated Location: (5235:131,163 [6] ) |Minute| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.cs index 0cfb0ce347..317625163e 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.cs @@ -77,6 +77,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { ThisShouldBeGenerated __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.mappings.txt index 7beb9caff3..acb55a2032 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/MultipleModels.mappings.txt @@ -1,10 +1,10 @@ Source Location: (7:0,7 [21] TestFiles/Input/MultipleModels.cshtml) |ThisShouldBeGenerated| -Generated Location: (2113:79,0 [21] ) +Generated Location: (2475:87,0 [21] ) |ThisShouldBeGenerated| Source Location: (37:1,7 [30] TestFiles/Input/MultipleModels.cshtml) |System.Collections.IEnumerable| -Generated Location: (2217:83,0 [30] ) +Generated Location: (2579:91,0 [30] ) |System.Collections.IEnumerable| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs index 9fefa71a10..0b863511e1 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.cs @@ -77,6 +77,14 @@ System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.UrlResol } ))(); ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.HeadTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { +System.Object __typeHelper = "Microsoft.AspNetCore.Mvc.Razor.TagHelpers.BodyTagHelper, Microsoft.AspNetCore.Mvc.Razor"; + } + ))(); + ((System.Action)(() => { IHtmlHelper __typeHelper = null; } ))(); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.mappings.txt b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.mappings.txt index ba80b72bff..97c297ced8 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.mappings.txt +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Host.Test/TestFiles/Output/DesignTime/_ViewImports.mappings.txt @@ -1,10 +1,10 @@ Source Location: (8:0,8 [19] TestFiles/Input/_ViewImports.cshtml) |IHtmlHelper| -Generated Location: (2088:79,0 [19] ) +Generated Location: (2450:87,0 [19] ) |IHtmlHelper| Source Location: (28:0,28 [5] TestFiles/Input/_ViewImports.cshtml) |Model| -Generated Location: (2204:83,14 [5] ) +Generated Location: (2566:91,14 [5] ) |Model| diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/TagHelpers/TagHelperComponentTagHelperTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/TagHelpers/TagHelperComponentTagHelperTest.cs new file mode 100644 index 0000000000..ae8d536120 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/TagHelpers/TagHelperComponentTagHelperTest.cs @@ -0,0 +1,292 @@ +// 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 System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Logging.Testing; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers +{ + public class TagHelperComponentTagHelperTest + { + [Fact] + public void Init_InvokesComponentsInitInCorrectOrder() + { + // Arrange + var tagHelperContext = new TagHelperContext( + "head", + allAttributes: new TagHelperAttributeList( + Enumerable.Empty()), + items: new Dictionary(), + uniqueId: "test"); + + var incrementer = 0; + var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new [] + { + new CallbackTagHelperComponent( + order: 2, + initCallback: () => + { + Assert.Equal(1, incrementer); + incrementer++; + }, + processAsyncCallback: null), + new CallbackTagHelperComponent( + order: 3, + initCallback: () => + { + Assert.Equal(2, incrementer); + incrementer++; + }, + processAsyncCallback: null), + new CallbackTagHelperComponent( + order: 1, + initCallback: () => + { + Assert.Equal(0, incrementer); + incrementer++; + }, + processAsyncCallback: null), + }, NullLoggerFactory.Instance); + + // Act + testTagHelperComponentTagHelper.Init(tagHelperContext); + + // Assert + Assert.Equal(3, incrementer); + } + + [Fact] + public async void ProcessAsync_InvokesComponentsProcessAsyncInCorrectOrder() + { + // Arrange + var tagHelperContext = new TagHelperContext( + "head", + allAttributes: new TagHelperAttributeList( + Enumerable.Empty()), + items: new Dictionary(), + uniqueId: "test"); + + var output = new TagHelperOutput( + "head", + attributes: new TagHelperAttributeList(), + getChildContentAsync: (useCachedResult, encoder) => Task.FromResult( + new DefaultTagHelperContent())); + + var incrementer = 0; + var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new [] + { + new CallbackTagHelperComponent( + order: 2, + initCallback: () => { }, + processAsyncCallback: () => + { + Assert.Equal(1, incrementer); + incrementer++; + }), + new CallbackTagHelperComponent( + order: 3, + initCallback: () => { }, + processAsyncCallback: () => + { + Assert.Equal(2, incrementer); + incrementer++; + }), + new CallbackTagHelperComponent( + order: 1, + initCallback: () => { }, + processAsyncCallback: () => + { + Assert.Equal(0, incrementer); + incrementer++; + }), + }, NullLoggerFactory.Instance); + + // Act + testTagHelperComponentTagHelper.Init(tagHelperContext); + await testTagHelperComponentTagHelper.ProcessAsync(tagHelperContext, output); + + // Assert + Assert.Equal(3, incrementer); + } + + [Fact] + public void Init_InvokesTagHelperComponentInit() + { + // Arrange + var tagHelperContext = new TagHelperContext( + "head", + allAttributes: new TagHelperAttributeList( + Enumerable.Empty()), + items: new Dictionary(), + uniqueId: "test"); + + var output = new TagHelperOutput( + "head", + attributes: new TagHelperAttributeList(), + getChildContentAsync: (useCachedResult, encoder) => Task.FromResult( + new DefaultTagHelperContent())); + + var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new [] + { + new TestTagHelperComponent() + }, NullLoggerFactory.Instance); + + // Act + testTagHelperComponentTagHelper.Init(tagHelperContext); + + // Assert + Assert.Equal("Value", tagHelperContext.Items["Key"]); + } + + [Fact] + public async Task ProcessAsync_InvokesTagHelperComponentProcessAsync() + { + // Arrange + var tagHelperContext = new TagHelperContext( + "head", + allAttributes: new TagHelperAttributeList( + Enumerable.Empty()), + items: new Dictionary(), + uniqueId: "test"); + + var output = new TagHelperOutput( + "head", + attributes: new TagHelperAttributeList(), + getChildContentAsync: (useCachedResult, encoder) => Task.FromResult( + new DefaultTagHelperContent())); + + var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new [] + { + new TestTagHelperComponent() + }, NullLoggerFactory.Instance); + + // Act + await testTagHelperComponentTagHelper.ProcessAsync(tagHelperContext, output); + + // Assert + Assert.Equal("Processed", output.PostContent.GetContent()); + } + + [Fact] + public void Init_LogsTagHelperComponentInitialized() + { + // Arrange + var sink = new TestSink(); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); + var tagHelperContext = new TagHelperContext( + "head", + allAttributes: new TagHelperAttributeList( + Enumerable.Empty()), + items: new Dictionary(), + uniqueId: "test"); + + var output = new TagHelperOutput( + "head", + attributes: new TagHelperAttributeList(), + getChildContentAsync: (useCachedResult, encoder) => Task.FromResult( + new DefaultTagHelperContent())); + + var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new [] + { + new TestTagHelperComponent() + }, loggerFactory); + + // Act + testTagHelperComponentTagHelper.Init(tagHelperContext); + + // Assert + Assert.Equal($"Tag helper component '{typeof(TestTagHelperComponent)}' initialized.", sink.Writes[0].State.ToString(), StringComparer.Ordinal); + } + + [Fact] + public async Task ProcessAsync_LogsTagHelperComponentProcessed() + { + // Arrange + var sink = new TestSink(); + var loggerFactory = new TestLoggerFactory(sink, enabled: true); + var tagHelperContext = new TagHelperContext( + "head", + allAttributes: new TagHelperAttributeList( + Enumerable.Empty()), + items: new Dictionary(), + uniqueId: "test"); + + var output = new TagHelperOutput( + "head", + attributes: new TagHelperAttributeList(), + getChildContentAsync: (useCachedResult, encoder) => Task.FromResult( + new DefaultTagHelperContent())); + + var testTagHelperComponentTagHelper = new TestTagHelperComponentTagHelper(new [] + { + new TestTagHelperComponent() + }, loggerFactory); + + // Act + await testTagHelperComponentTagHelper.ProcessAsync(tagHelperContext, output); + + // Assert + Assert.Equal($"Tag helper component '{typeof(TestTagHelperComponent)}' processed.", sink.Writes[0].State.ToString(), StringComparer.Ordinal); + } + + private class TestTagHelperComponentTagHelper : TagHelperComponentTagHelper + { + public TestTagHelperComponentTagHelper( + IEnumerable components, + ILoggerFactory loggerFactory) + : base(components, loggerFactory) + { + } + } + + private class CallbackTagHelperComponent : ITagHelperComponent + { + private readonly Action _initCallback; + private readonly Action _processAsyncCallback; + private readonly int _order; + + public CallbackTagHelperComponent(int order, Action initCallback, Action processAsyncCallback) + { + _initCallback = initCallback; + _processAsyncCallback = processAsyncCallback; + _order = order; + } + + public int Order => _order; + + public void Init(TagHelperContext context) + { + _initCallback(); + } + + public Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + _processAsyncCallback(); + return Task.CompletedTask; + } + } + + private class TestTagHelperComponent : ITagHelperComponent + { + public int Order => 1; + + public void Init(TagHelperContext context) + { + context.Items["Key"] = "Value"; + } + + public Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + output.PostContent.AppendHtml("Processed"); + return Task.CompletedTask; + } + } + } +} diff --git a/test/WebSites/RazorWebSite/Controllers/TagHelperComponentController.cs b/test/WebSites/RazorWebSite/Controllers/TagHelperComponentController.cs new file mode 100644 index 0000000000..d3be1d2fbd --- /dev/null +++ b/test/WebSites/RazorWebSite/Controllers/TagHelperComponentController.cs @@ -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 Microsoft.AspNetCore.Mvc; + +namespace RazorWebSite +{ + public class TagHelperComponentController : Controller + { + // GET: // + public IActionResult GetHead() + { + return View("Head"); + } + + public IActionResult GetBody() + { + return View("Body"); + } + } +} diff --git a/test/WebSites/RazorWebSite/Services/TestBodyTagHelperComponent.cs b/test/WebSites/RazorWebSite/Services/TestBodyTagHelperComponent.cs new file mode 100644 index 0000000000..cc31c525e1 --- /dev/null +++ b/test/WebSites/RazorWebSite/Services/TestBodyTagHelperComponent.cs @@ -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 System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace RazorWebSite +{ + public class TestBodyTagHelperComponent : TagHelperComponent + { + public override int Order => 1; + + public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + if (string.Equals(context.TagName, "body", StringComparison.Ordinal) && output.Attributes.ContainsName("inject")) + { + output.PostContent.AppendHtml(""); + } + + return Task.FromResult(0); + } + } +} diff --git a/test/WebSites/RazorWebSite/Services/TestHeadTagHelperComponent.cs b/test/WebSites/RazorWebSite/Services/TestHeadTagHelperComponent.cs new file mode 100644 index 0000000000..6242cf6b71 --- /dev/null +++ b/test/WebSites/RazorWebSite/Services/TestHeadTagHelperComponent.cs @@ -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 System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace RazorWebSite +{ + public class TestHeadTagHelperComponent : TagHelperComponent + { + public override int Order => 1; + + public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + if (string.Equals(context.TagName, "head", StringComparison.Ordinal) && output.Attributes.ContainsName("inject")) + { + output.PostContent.AppendHtml(""); + } + + return Task.FromResult(0); + } + } +} diff --git a/test/WebSites/RazorWebSite/Startup.cs b/test/WebSites/RazorWebSite/Startup.cs index 7a112f7dd4..c3061920cc 100644 --- a/test/WebSites/RazorWebSite/Startup.cs +++ b/test/WebSites/RazorWebSite/Startup.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; @@ -20,6 +21,9 @@ namespace RazorWebSite { var updateableFileProvider = new UpdateableFileProvider(); services.AddSingleton(updateableFileProvider); + services.AddSingleton(); + services.AddSingleton(); + services .AddMvc() .AddRazorOptions(options => diff --git a/test/WebSites/RazorWebSite/Views/TagHelperComponent/Body.cshtml b/test/WebSites/RazorWebSite/Views/TagHelperComponent/Body.cshtml new file mode 100644 index 0000000000..fa0abd5f31 --- /dev/null +++ b/test/WebSites/RazorWebSite/Views/TagHelperComponent/Body.cshtml @@ -0,0 +1,3 @@ + +Hello from Body Tag Helper Component + \ No newline at end of file diff --git a/test/WebSites/RazorWebSite/Views/TagHelperComponent/Head.cshtml b/test/WebSites/RazorWebSite/Views/TagHelperComponent/Head.cshtml new file mode 100644 index 0000000000..180899778e --- /dev/null +++ b/test/WebSites/RazorWebSite/Views/TagHelperComponent/Head.cshtml @@ -0,0 +1,3 @@ + +Hello from Head Tag Helper Component + \ No newline at end of file