Add `ModelMetadata.HtmlEncode` property
- use new `ModelMetadata.HtmlEncode` property in HTML helpers - specifically in default HTML display and editor object templates (e.g. `@Html.DisplayFor()`) when value is non-`null` and the template is invoked with template depth greater than 1 - similar to MVC 5.2 commit [2b12791aee4f](https://aspnetwebstack.codeplex.com/SourceControl/changeset/2b12791aee4ffc56c7928b623bb45ee425813021) nits: - remove dupe `null` check in `DefaultDisplayTemplates.ObjectTemplate()` - move backing fields initialized with constants together in `ModelMetadata`
This commit is contained in:
parent
d5515bfbb6
commit
90e41b905a
|
|
@ -213,7 +213,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
if (templateInfo.TemplateDepth > 1)
|
||||
{
|
||||
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
|
||||
var text = modelMetadata.SimpleDisplayText;
|
||||
if (modelMetadata.HtmlEncode)
|
||||
{
|
||||
text = html.Encode(text);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
|
||||
|
|
|
|||
|
|
@ -232,7 +232,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
if (templateInfo.TemplateDepth > 1)
|
||||
{
|
||||
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
|
||||
if (modelMetadata.Model == null)
|
||||
{
|
||||
return modelMetadata.NullDisplayText;
|
||||
}
|
||||
|
||||
var text = modelMetadata.SimpleDisplayText;
|
||||
if (modelMetadata.HtmlEncode)
|
||||
{
|
||||
text = html.Encode(text);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
|
||||
|
|
|
|||
|
|
@ -205,6 +205,25 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.ComputeHideSurroundingHtml();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate <see cref="ModelMetadata.HtmlEncode"/> based on presence of a
|
||||
/// <see cref="DisplayFormatAttribute"/> and its <see cref="DisplayFormatAttribute.HtmlEncode"/> value.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Calculated <see cref="ModelMetadata.HtmlEncode"/> value. <c>false</c> if a
|
||||
/// <see cref="DisplayFormatAttribute"/> exists and its <see cref="DisplayFormatAttribute.HtmlEncode"/> value
|
||||
/// is <c>false</c>. <c>true</c> otherwise.
|
||||
/// </returns>
|
||||
protected override bool ComputeHtmlEncode()
|
||||
{
|
||||
if (PrototypeCache.DisplayFormat != null)
|
||||
{
|
||||
return PrototypeCache.DisplayFormat.HtmlEncode;
|
||||
}
|
||||
|
||||
return base.ComputeHtmlEncode();
|
||||
}
|
||||
|
||||
protected override bool ComputeIsReadOnly()
|
||||
{
|
||||
if (PrototypeCache.Editable != null)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private string _editFormatString;
|
||||
private bool _hasNonDefaultEditFormat;
|
||||
private bool _hideSurroundingHtml;
|
||||
private bool _htmlEncode;
|
||||
private bool _isReadOnly;
|
||||
private bool _isComplexType;
|
||||
private bool _isRequired;
|
||||
|
|
@ -39,6 +40,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private bool _editFormatStringComputed;
|
||||
private bool _hasNonDefaultEditFormatComputed;
|
||||
private bool _hideSurroundingHtmlComputed;
|
||||
private bool _htmlEncodeComputed;
|
||||
private bool _isReadOnlyComputed;
|
||||
private bool _isComplexTypeComputed;
|
||||
private bool _isRequiredComputed;
|
||||
|
|
@ -252,6 +254,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed override bool HtmlEncode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_htmlEncodeComputed)
|
||||
{
|
||||
_htmlEncode = ComputeHtmlEncode();
|
||||
_htmlEncodeComputed = true;
|
||||
}
|
||||
|
||||
return _htmlEncode;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_htmlEncode = value;
|
||||
_htmlEncodeComputed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed override bool IsReadOnly
|
||||
{
|
||||
get
|
||||
|
|
@ -419,6 +442,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
return base.HideSurroundingHtml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the <see cref="HtmlEncode"/> value.
|
||||
/// </summary>
|
||||
/// <returns>Calculated <see cref="HtmlEncode"/> value.</returns>
|
||||
protected virtual bool ComputeHtmlEncode()
|
||||
{
|
||||
return base.HtmlEncode;
|
||||
}
|
||||
|
||||
protected virtual bool ComputeIsReadOnly()
|
||||
{
|
||||
return base.IsReadOnly;
|
||||
|
|
|
|||
|
|
@ -19,17 +19,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
private EfficientTypePropertyKey<Type, string> _cacheKey;
|
||||
|
||||
// Backing fields for virtual properties with default values.
|
||||
private bool _convertEmptyStringToNull;
|
||||
private bool _isRequired;
|
||||
private bool _convertEmptyStringToNull = true;
|
||||
private bool _htmlEncode = true;
|
||||
private bool _showForDisplay = true;
|
||||
private bool _showForEdit = true;
|
||||
|
||||
private object _model;
|
||||
private Func<object> _modelAccessor;
|
||||
private int _order = DefaultOrder;
|
||||
private bool _isRequired;
|
||||
private IEnumerable<ModelMetadata> _properties;
|
||||
private Type _realModelType;
|
||||
private string _simpleDisplayText;
|
||||
private bool _showForDisplay = true;
|
||||
private bool _showForEdit = true;
|
||||
|
||||
public ModelMetadata([NotNull] IModelMetadataProvider provider,
|
||||
Type containerType,
|
||||
|
|
@ -43,7 +44,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
_modelAccessor = modelAccessor;
|
||||
_modelType = modelType;
|
||||
_propertyName = propertyName;
|
||||
_convertEmptyStringToNull = true;
|
||||
_isRequired = !modelType.AllowsNullValue();
|
||||
}
|
||||
|
||||
|
|
@ -111,6 +111,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// </summary>
|
||||
public virtual bool HasNonDefaultEditFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the value should be HTML-encoded.
|
||||
/// </summary>
|
||||
/// <value>If <c>true</c>, value should be HTML-encoded. Default is <c>true</c>.</value>
|
||||
public virtual bool HtmlEncode
|
||||
{
|
||||
get { return _htmlEncode; }
|
||||
set { _htmlEncode = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the "HiddenInput" display template should return
|
||||
/// <c>string.Empty</c> (not the expression value) and whether the "HiddenInput" editor template should not
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
// 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.AspNet.Mvc.ModelBinding;
|
||||
|
|
@ -14,6 +13,33 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
{
|
||||
public class DefaultDisplayTemplateTests
|
||||
{
|
||||
// Input value; HTML encode; expected value.
|
||||
public static TheoryData<string, bool, string> HtmlEncodeData
|
||||
{
|
||||
get
|
||||
{
|
||||
return new TheoryData<string, bool, string>
|
||||
{
|
||||
{ "Simple Display Text", false, "Simple Display Text" },
|
||||
{ "Simple Display Text", true, "Simple Display Text" },
|
||||
{ "<blink>text</blink>", false, "<blink>text</blink>" },
|
||||
{ "<blink>text</blink>", true, "<blink>text</blink>" },
|
||||
{ "&'\"", false, "&'\"" },
|
||||
{ "&'\"", true, "&'"" },
|
||||
{ " ¡ÿĀ", false, " ¡ÿĀ" }, // high ASCII
|
||||
{ " ¡ÿĀ", true, " ¡ÿĀ" },
|
||||
{ "Chinese西雅图Chars", false, "Chinese西雅图Chars" },
|
||||
{ "Chinese西雅图Chars", true, "Chinese西雅图Chars" },
|
||||
{ "UnicodeFormatChar", false, "UnicodeFormatChar" }, // class Cf
|
||||
{ "UnicodeFormatChar", true, "UnicodeFormatChar" },
|
||||
{ "UnicodeῼTitlecaseῼChar", false, "UnicodeῼTitlecaseῼChar" }, // class Lt
|
||||
{ "UnicodeῼTitlecaseῼChar", true, "UnicodeῼTitlecaseῼChar" },
|
||||
{ "UnicodeःCombiningःChar", false, "UnicodeःCombiningःChar" }, // class Mc
|
||||
{ "UnicodeःCombiningःChar", true, "UnicodeःCombiningःChar" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectTemplateDisplaysSimplePropertiesOnObjectByDefault()
|
||||
{
|
||||
|
|
@ -54,8 +80,12 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal(metadata.NullDisplayText, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne()
|
||||
[Theory]
|
||||
[MemberData(nameof(HtmlEncodeData))]
|
||||
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne(
|
||||
string simpleDisplayText,
|
||||
bool htmlEncode,
|
||||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var model = new DefaultTemplatesUtilities.ObjectTemplateModel();
|
||||
|
|
@ -63,7 +93,8 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
var metadata =
|
||||
new EmptyModelMetadataProvider()
|
||||
.GetMetadataForType(() => model, typeof(DefaultTemplatesUtilities.ObjectTemplateModel));
|
||||
metadata.SimpleDisplayText = "Simple Display Text";
|
||||
metadata.HtmlEncode = htmlEncode;
|
||||
metadata.SimpleDisplayText = simpleDisplayText;
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
html.ViewData.TemplateInfo.AddVisited("foo");
|
||||
html.ViewData.TemplateInfo.AddVisited("bar");
|
||||
|
|
@ -72,7 +103,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
var result = DefaultDisplayTemplates.ObjectTemplate(html);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(metadata.SimpleDisplayText, result);
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -115,8 +115,12 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
Assert.Equal(metadata.NullDisplayText, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne()
|
||||
[Theory]
|
||||
[MemberData(nameof(DefaultDisplayTemplateTests.HtmlEncodeData), MemberType = typeof(DefaultDisplayTemplateTests))]
|
||||
public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne(
|
||||
string simpleDisplayText,
|
||||
bool htmlEncode,
|
||||
string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var model = new DefaultTemplatesUtilities.ObjectTemplateModel();
|
||||
|
|
@ -124,9 +128,10 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
var metadata =
|
||||
new EmptyModelMetadataProvider()
|
||||
.GetMetadataForType(() => model, typeof(DefaultTemplatesUtilities.ObjectTemplateModel));
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
metadata.HtmlEncode = htmlEncode;
|
||||
metadata.NullDisplayText = "Null Display Text";
|
||||
metadata.SimpleDisplayText = "Simple Display Text";
|
||||
metadata.SimpleDisplayText = simpleDisplayText;
|
||||
html.ViewData.ModelMetadata = metadata;
|
||||
html.ViewData.TemplateInfo.AddVisited("foo");
|
||||
html.ViewData.TemplateInfo.AddVisited("bar");
|
||||
|
||||
|
|
@ -134,7 +139,7 @@ namespace Microsoft.AspNet.Mvc.Core
|
|||
var result = DefaultEditorTemplates.ObjectTemplate(html);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(metadata.SimpleDisplayText, result);
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.True(metadata.ConvertEmptyStringToNull);
|
||||
Assert.False(metadata.HasNonDefaultEditFormat);
|
||||
Assert.False(metadata.HideSurroundingHtml);
|
||||
Assert.True(metadata.HtmlEncode);
|
||||
Assert.True(metadata.IsComplexType);
|
||||
Assert.False(metadata.IsReadOnly);
|
||||
Assert.False(metadata.IsRequired);
|
||||
|
|
@ -157,6 +158,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
metadata => metadata.HasNonDefaultEditFormat,
|
||||
true
|
||||
},
|
||||
{
|
||||
new DisplayFormatAttribute { HtmlEncode = false },
|
||||
metadata => metadata.HtmlEncode,
|
||||
false
|
||||
},
|
||||
{
|
||||
new DisplayFormatAttribute { HtmlEncode = true },
|
||||
metadata => metadata.HtmlEncode,
|
||||
true
|
||||
},
|
||||
{
|
||||
new EditableAttribute(allowEdit: false),
|
||||
metadata => metadata.IsReadOnly,
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{ m => m.ConvertEmptyStringToNull = false, m => m.ConvertEmptyStringToNull, false },
|
||||
{ m => m.HasNonDefaultEditFormat = true, m => m.HasNonDefaultEditFormat, true },
|
||||
{ m => m.HideSurroundingHtml = true, m => m.HideSurroundingHtml, true },
|
||||
{ m => m.HtmlEncode = false, m => m.HtmlEncode, false },
|
||||
{ m => m.IsReadOnly = true, m => m.IsReadOnly, true },
|
||||
{ m => m.IsRequired = true, m => m.IsRequired, true },
|
||||
{ m => m.ShowForDisplay = false, m => m.ShowForDisplay, false },
|
||||
|
|
@ -59,6 +60,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
Assert.True(metadata.ConvertEmptyStringToNull);
|
||||
Assert.False(metadata.HasNonDefaultEditFormat);
|
||||
Assert.False(metadata.HideSurroundingHtml);
|
||||
Assert.True(metadata.HtmlEncode);
|
||||
Assert.False(metadata.IsComplexType);
|
||||
Assert.False(metadata.IsNullableValueType);
|
||||
Assert.False(metadata.IsReadOnly);
|
||||
|
|
|
|||
Loading…
Reference in New Issue