Skip to content

Commit 2b12791

Browse files
committed
Add ModelMetadata.HtmlEncode property
- use new `ModelMetadata.HtmlEncode` property in HTML helpers - conditionally 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 - unconditionally in `@Html.DisplayText()` and `@Html.DisplayTextFor()` - test new property and its use Also test `DisplayTextExtensions` - unit test gap
1 parent f9a064c commit 2b12791

13 files changed

+555
-14
lines changed

src/System.Web.Mvc/CachedDataAnnotationsModelMetadata.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ protected override bool ComputeHideSurroundingHtml()
123123
: base.ComputeHideSurroundingHtml();
124124
}
125125

126+
protected override bool ComputeHtmlEncode()
127+
{
128+
return (PrototypeCache.DisplayFormat != null)
129+
? PrototypeCache.DisplayFormat.HtmlEncode
130+
: base.ComputeHtmlEncode();
131+
}
132+
126133
protected override bool ComputeIsReadOnly()
127134
{
128135
if (PrototypeCache.Editable != null)

src/System.Web.Mvc/CachedModelMetadata.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public abstract class CachedModelMetadata<TPrototypeCache> : ModelMetadata
2020
private string _editFormatString;
2121
private bool _hasNonDefaultEditFormat;
2222
private bool _hideSurroundingHtml;
23+
private bool _htmlEncode;
2324
private bool _isReadOnly;
2425
private bool _isRequired;
2526
private string _nullDisplayText;
@@ -38,6 +39,7 @@ public abstract class CachedModelMetadata<TPrototypeCache> : ModelMetadata
3839
private bool _editFormatStringComputed;
3940
private bool _hasNonDefaultEditFormatComputed;
4041
private bool _hideSurroundingHtmlComputed;
42+
private bool _htmlEncodeComputed;
4143
private bool _isReadOnlyComputed;
4244
private bool _isRequiredComputed;
4345
private bool _nullDisplayTextComputed;
@@ -207,6 +209,24 @@ public sealed override bool HideSurroundingHtml
207209
}
208210
}
209211

212+
public sealed override bool HtmlEncode
213+
{
214+
get
215+
{
216+
if (!_htmlEncodeComputed)
217+
{
218+
_htmlEncode = ComputeHtmlEncode();
219+
_htmlEncodeComputed = true;
220+
}
221+
return _htmlEncode;
222+
}
223+
set
224+
{
225+
_htmlEncode = value;
226+
_htmlEncodeComputed = true;
227+
}
228+
}
229+
210230
public sealed override bool IsReadOnly
211231
{
212232
get
@@ -421,6 +441,11 @@ protected virtual bool ComputeHideSurroundingHtml()
421441
return base.HideSurroundingHtml;
422442
}
423443

444+
protected virtual bool ComputeHtmlEncode()
445+
{
446+
return base.HtmlEncode;
447+
}
448+
424449
protected virtual bool ComputeIsReadOnly()
425450
{
426451
return base.IsReadOnly;

src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ private static void SetFromDataTypeAndDisplayAttributes(DataAnnotationsModelMeta
121121
result.NullDisplayText = displayFormatAttribute.NullDisplayText;
122122
result.DisplayFormatString = displayFormatAttribute.DataFormatString;
123123
result.ConvertEmptyStringToNull = displayFormatAttribute.ConvertEmptyStringToNull;
124+
result.HtmlEncode = displayFormatAttribute.HtmlEncode;
124125

125126
if (displayFormatAttribute.ApplyFormatInEditMode)
126127
{

src/System.Web.Mvc/Html/DefaultDisplayTemplates.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,13 @@ internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateH
174174
if (templateInfo.TemplateDepth > 1)
175175
{
176176
// DDB #224751
177-
return modelMetadata.SimpleDisplayText;
177+
string text = modelMetadata.SimpleDisplayText;
178+
if (modelMetadata.HtmlEncode)
179+
{
180+
text = html.Encode(text);
181+
}
182+
183+
return text;
178184
}
179185

180186
foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))

src/System.Web.Mvc/Html/DefaultEditorTemplates.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,19 @@ internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateH
230230

231231
if (templateInfo.TemplateDepth > 1)
232232
{
233+
if (modelMetadata.Model == null)
234+
{
235+
return modelMetadata.NullDisplayText;
236+
}
237+
233238
// DDB #224751
234-
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
239+
string text = modelMetadata.SimpleDisplayText;
240+
if (modelMetadata.HtmlEncode)
241+
{
242+
text = html.Encode(text);
243+
}
244+
245+
return text;
235246
}
236247

237248
foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))

src/System.Web.Mvc/Html/DisplayTextExtensions.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,24 @@ public static class DisplayTextExtensions
99
{
1010
public static MvcHtmlString DisplayText(this HtmlHelper html, string name)
1111
{
12-
return DisplayTextHelper(ModelMetadata.FromStringExpression(name, html.ViewContext.ViewData));
12+
return DisplayTextHelper(html, ModelMetadata.FromStringExpression(name, html.ViewContext.ViewData));
1313
}
1414

1515
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
1616
public static MvcHtmlString DisplayTextFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression)
1717
{
18-
return DisplayTextHelper(ModelMetadata.FromLambdaExpression(expression, html.ViewData));
18+
return DisplayTextHelper(html, ModelMetadata.FromLambdaExpression(expression, html.ViewData));
1919
}
2020

21-
private static MvcHtmlString DisplayTextHelper(ModelMetadata metadata)
21+
private static MvcHtmlString DisplayTextHelper(HtmlHelper html, ModelMetadata metadata)
2222
{
23-
return MvcHtmlString.Create(metadata.SimpleDisplayText);
23+
string text = metadata.SimpleDisplayText;
24+
if (metadata.HtmlEncode)
25+
{
26+
text = html.Encode(text);
27+
}
28+
29+
return MvcHtmlString.Create(text);
2430
}
2531
}
2632
}

src/System.Web.Mvc/ModelMetadata.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class ModelMetadata
2828
/// </summary>
2929
private Dictionary<string, object> _additionalValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
3030
private bool _convertEmptyStringToNull = true;
31+
private bool _htmlEncode = true;
3132
private bool _isRequired;
3233
private object _model;
3334
private Func<object> _modelAccessor;
@@ -96,6 +97,12 @@ public virtual bool ConvertEmptyStringToNull
9697

9798
public virtual bool HideSurroundingHtml { get; set; }
9899

100+
public virtual bool HtmlEncode
101+
{
102+
get { return _htmlEncode; }
103+
set { _htmlEncode = value; }
104+
}
105+
99106
public virtual bool IsComplexType
100107
{
101108
get { return !(TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string))); }

test/System.Web.Mvc.Test/Html/Test/DefaultDisplayTemplatesTest.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -454,14 +454,20 @@ public void ObjectTemplateDisplaysNullDisplayTextWhenObjectIsNull()
454454
Assert.Equal(metadata.NullDisplayText, result);
455455
}
456456

457-
[Fact]
458-
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne()
457+
[Theory]
458+
[PropertyData("DisplayTextData", PropertyType = typeof(DisplayTextExtensionsTest))]
459+
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne(
460+
string simpleDisplayText,
461+
bool htmlEncode,
462+
string expectedResult)
459463
{
460464
// Arrange
461465
ObjectTemplateModel model = new ObjectTemplateModel();
462466
HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
463467
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(ObjectTemplateModel));
464-
metadata.SimpleDisplayText = "Simple Display Text";
468+
metadata.SimpleDisplayText = simpleDisplayText;
469+
metadata.HtmlEncode = htmlEncode;
470+
465471
html.ViewData.ModelMetadata = metadata;
466472
html.ViewData.TemplateInfo.VisitedObjects.Add("foo");
467473
html.ViewData.TemplateInfo.VisitedObjects.Add("bar");
@@ -470,7 +476,7 @@ public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanO
470476
string result = DefaultDisplayTemplates.ObjectTemplate(html, SpyCallback);
471477

472478
// Assert
473-
Assert.Equal(metadata.SimpleDisplayText, result);
479+
Assert.Equal(expectedResult, result);
474480
}
475481

476482
[Fact]

test/System.Web.Mvc.Test/Html/Test/DefaultEditorTemplatesTest.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -697,24 +697,30 @@ public void ObjectTemplateDisplaysNullDisplayTextWithNullModelAndTemplateDepthGr
697697
Assert.Equal(metadata.NullDisplayText, result);
698698
}
699699

700-
[Fact]
701-
public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne()
700+
[Theory]
701+
[PropertyData("DisplayTextData", PropertyType = typeof(DisplayTextExtensionsTest))]
702+
public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne(
703+
string simpleDisplayText,
704+
bool htmlEncode,
705+
string expectedResult)
702706
{
703707
// Arrange
704708
ObjectTemplateModel model = new ObjectTemplateModel();
705709
HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
706710
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(ObjectTemplateModel));
707711
html.ViewData.ModelMetadata = metadata;
708712
metadata.NullDisplayText = "Null Display Text";
709-
metadata.SimpleDisplayText = "Simple Display Text";
713+
metadata.SimpleDisplayText = simpleDisplayText;
714+
metadata.HtmlEncode = htmlEncode;
715+
710716
html.ViewData.TemplateInfo.VisitedObjects.Add("foo");
711717
html.ViewData.TemplateInfo.VisitedObjects.Add("bar");
712718

713719
// Act
714720
string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);
715721

716722
// Assert
717-
Assert.Equal(metadata.SimpleDisplayText, result);
723+
Assert.Equal(expectedResult, result);
718724
}
719725

720726
// PasswordTemplate

0 commit comments

Comments
 (0)