diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/DefaultEditorTemplates.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/DefaultEditorTemplates.cs index 09c2c60e97..408448c651 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/DefaultEditorTemplates.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Internal/DefaultEditorTemplates.cs @@ -20,6 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal public static class DefaultEditorTemplates { private const string HtmlAttributeKey = "htmlAttributes"; + private const string UsePasswordValue = "Switch.Microsoft.AspNetCore.Mvc.UsePasswordValue"; public static IHtmlContent BooleanTemplate(IHtmlHelper htmlHelper) { @@ -312,9 +313,15 @@ public static IHtmlContent ObjectTemplate(IHtmlHelper htmlHelper) public static IHtmlContent PasswordTemplate(IHtmlHelper htmlHelper) { + object value = null; + if (AppContext.TryGetSwitch(UsePasswordValue, out var usePasswordValue) && usePasswordValue) + { + value = htmlHelper.ViewData.TemplateInfo.FormattedModelValue; + } + return htmlHelper.Password( expression: null, - value: htmlHelper.ViewData.TemplateInfo.FormattedModelValue, + value: value, htmlAttributes: CreateHtmlAttributes(htmlHelper, "text-box single-line password")); } diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/DefaultEditorTemplatesTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/DefaultEditorTemplatesTest.cs index e7e1b568bc..793f7a176e 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/DefaultEditorTemplatesTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Internal/DefaultEditorTemplatesTest.cs @@ -521,6 +521,55 @@ public void MultilineTextTemplate_ReturnsTextArea() Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); } + [Fact] + public void PasswordTemplate_ReturnsInputElement_IgnoresValues() + { + // Arrange + var expected = ""; + + // Template ignores Model. + var model = "Model string"; + + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model); + var viewData = helper.ViewData; + var templateInfo = viewData.TemplateInfo; + templateInfo.HtmlFieldPrefix = "FieldPrefix"; + + // Template ignores FormattedModelValue, ModelState and ViewData. + templateInfo.FormattedModelValue = "Formatted string"; + viewData.ModelState.SetModelValue("FieldPrefix", "Raw model string", "Attempted model string"); + viewData["FieldPrefix"] = "ViewData string"; + + // Act + var result = DefaultEditorTemplates.PasswordTemplate(helper); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + + [Fact] + public void PasswordTemplate_ReturnsInputElement_UsesHtmlAttributes() + { + // Arrange + var expected = ""; + var helper = DefaultTemplatesUtilities.GetHtmlHelper(model: null); + var viewData = helper.ViewData; + var templateInfo = viewData.TemplateInfo; + templateInfo.HtmlFieldPrefix = "FieldPrefix"; + + viewData["htmlAttributes"] = new { @class = "super", value = "Html attributes string" }; + + // Act + var result = DefaultEditorTemplates.PasswordTemplate(helper); + + // Assert + Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(result)); + } + [Theory] [MemberData(nameof(TemplateNameData))] public void Editor_CallsExpectedHtmlHelper(string templateName, string expectedResult)