diff --git a/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs b/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs index 6dc9bfe722..4bac5c8fc7 100644 --- a/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs +++ b/src/Mvc/Mvc.TagHelpers/src/ComponentTagHelper.cs @@ -14,14 +14,16 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// /// A that renders a Razor component. /// - [HtmlTargetElement("component", Attributes = ComponentTypeName, TagStructure = TagStructure.WithoutEndTag)] + [HtmlTargetElement(TagHelperName, Attributes = ComponentTypeName, TagStructure = TagStructure.WithoutEndTag)] public sealed class ComponentTagHelper : TagHelper { + private const string TagHelperName = "component"; private const string ComponentParameterName = "params"; private const string ComponentParameterPrefix = "param-"; private const string ComponentTypeName = "type"; private const string RenderModeName = "render-mode"; private IDictionary _parameters; + private RenderMode? _renderMode; /// /// Gets or sets the for the current request. @@ -54,7 +56,29 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers /// Gets or sets the /// [HtmlAttributeName(RenderModeName)] - public RenderMode RenderMode { get; set; } + public RenderMode RenderMode + { + get => _renderMode ?? default; + set + { + switch (value) + { + case RenderMode.Server: + case RenderMode.ServerPrerendered: + case RenderMode.Static: + _renderMode = value; + break; + + default: + throw new ArgumentException( + message: Resources.FormatInvalidEnumArgument( + nameof(value), + value, + typeof(RenderMode).FullName), + paramName: nameof(value)); + } + } + } /// public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) @@ -69,6 +93,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers throw new ArgumentNullException(nameof(output)); } + if (_renderMode is null) + { + throw new ArgumentException(Resources.FormatAttributeIsRequired(RenderModeName, TagHelperName), nameof(RenderMode)); + } + var componentRenderer = ViewContext.HttpContext.RequestServices.GetRequiredService(); var result = await componentRenderer.RenderComponentAsync(ViewContext, ComponentType, RenderMode, _parameters); diff --git a/src/Mvc/Mvc.TagHelpers/src/Resources.resx b/src/Mvc/Mvc.TagHelpers/src/Resources.resx index 96c56dff7f..7a69f0d95f 100644 --- a/src/Mvc/Mvc.TagHelpers/src/Resources.resx +++ b/src/Mvc/Mvc.TagHelpers/src/Resources.resx @@ -162,4 +162,7 @@ The fallback partial view '{0}' was not found. The following locations were searched:{1} + + A value for the '{0}' attribute must be supplied to the '{1}' tag helper. + \ No newline at end of file diff --git a/src/Mvc/Mvc.TagHelpers/test/ComponentTagHelperTest.cs b/src/Mvc/Mvc.TagHelpers/test/ComponentTagHelperTest.cs index 5c1aff4a7e..fe8db979bd 100644 --- a/src/Mvc/Mvc.TagHelpers/test/ComponentTagHelperTest.cs +++ b/src/Mvc/Mvc.TagHelpers/test/ComponentTagHelperTest.cs @@ -3,13 +3,13 @@ using System; using System.Collections.Generic; -using System.IO.Pipes; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; @@ -25,6 +25,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers var tagHelper = new ComponentTagHelper { ViewContext = GetViewContext(), + RenderMode = RenderMode.Static, }; var context = GetTagHelperContext(); var output = GetTagHelperOutput(); @@ -38,6 +39,24 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers Assert.Null(output.TagName); } + [Fact] + public async Task ProcessAsync_WithoutSpecifyingRenderMode_ThrowsError() + { + // Arrange + var tagHelper = new ComponentTagHelper + { + ViewContext = GetViewContext(), + }; + var context = GetTagHelperContext(); + var output = GetTagHelperOutput(); + + // Act & Assert + await ExceptionAssert.ThrowsArgumentAsync( + () => tagHelper.ProcessAsync(context, output), + nameof(RenderMode), + "A value for the 'render-mode' attribute must be supplied to the 'component' tag helper."); + } + private static TagHelperContext GetTagHelperContext() { return new TagHelperContext(