Calculate `ModelMetadata.DataTypeName` based on metadata

- helps MVC helpers like `@Html.EditorFor()` select the correct template
- #933

nit: add XML doc for `DataTypeName` in base `ModelMetadata`
This commit is contained in:
Doug Bunting 2014-10-01 13:04:54 -07:00
parent 12477c9f52
commit a5600a74a3
4 changed files with 131 additions and 2 deletions

View File

@ -12,6 +12,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// is correct.
public class CachedDataAnnotationsModelMetadata : CachedModelMetadata<CachedDataAnnotationsMetadataAttributes>
{
private static readonly string HtmlName = DataType.Html.ToString();
private bool _isEditFormatStringFromCache;
public CachedDataAnnotationsModelMetadata(CachedDataAnnotationsModelMetadata prototype,
@ -47,6 +48,31 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
: base.ComputeNullDisplayText();
}
/// <summary>
/// Calculate <see cref="ModelMetadata.DataTypeName"/> based on presence of a <see cref="DataTypeAttribute"/>
/// and its <see cref="DataTypeAttribute.GetDataTypeName()"/> method.
/// </summary>
/// <returns>
/// Calculated <see cref="ModelMetadata.DataTypeName"/> value.
/// <see cref="DataTypeAttribute.GetDataTypeName()"/> value if a <see cref="DataTypeAttribute"/> exists.
/// <c>"Html"</c> if a <see cref="DisplayFormatAttribute"/> exists with its
/// <see cref="DisplayFormatAttribute.HtmlEncode"/> value <c>false</c>. <c>null</c> otherwise.
/// </returns>
protected override string ComputeDataTypeName()
{
if (PrototypeCache.DataType != null)
{
return PrototypeCache.DataType.GetDataTypeName();
}
if (PrototypeCache.DisplayFormat != null && !PrototypeCache.DisplayFormat.HtmlEncode)
{
return HtmlName;
}
return base.ComputeDataTypeName();
}
protected override string ComputeDescription()
{
return PrototypeCache.Display != null

View File

@ -17,6 +17,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
private bool _convertEmptyStringToNull;
private string _nullDisplayText;
private string _dataTypeName;
private string _description;
private string _displayFormatString;
private string _displayName;
@ -31,6 +32,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private bool _convertEmptyStringToNullComputed;
private bool _nullDisplayTextComputed;
private bool _dataTypeNameComputed;
private bool _descriptionComputed;
private bool _displayFormatStringComputed;
private bool _displayNameComputed;
@ -105,6 +107,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
}
/// <inheritdoc />
public sealed override string DataTypeName
{
get
{
if (!_dataTypeNameComputed)
{
_dataTypeName = ComputeDataTypeName();
_dataTypeNameComputed = true;
}
return _dataTypeName;
}
set
{
_dataTypeName = value;
_dataTypeNameComputed = true;
}
}
public sealed override string Description
{
get
@ -338,6 +361,15 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return base.NullDisplayText;
}
/// <summary>
/// Calculate the <see cref="DataTypeName"/> value.
/// </summary>
/// <returns>Calculated <see cref="DataTypeName"/> value.</returns>
protected virtual string ComputeDataTypeName()
{
return base.DataTypeName;
}
protected virtual string ComputeDescription()
{
return base.Description;

View File

@ -59,6 +59,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
set { _convertEmptyStringToNull = value; }
}
/// <summary>
/// Gets or sets the name of the <see cref="Model"/>'s datatype. Overrides <see cref="ModelType"/> in some
/// display scenarios.
/// </summary>
/// <value><c>null</c> unless set manually or through additional metadata e.g. attributes.</value>
public virtual string DataTypeName { get; set; }
public virtual string Description { get; set; }

View File

@ -56,6 +56,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
return new TheoryData<Attribute, Func<ModelMetadata, string>>
{
{
new DataTypeAttribute("value"), metadata => metadata.DataTypeName
},
{
new DataTypeWithCustomDisplayFormat(), metadata => metadata.DisplayFormatString
},
@ -207,6 +210,69 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Equal(expectedResult, result);
}
[Fact]
public void DataTypeName_Null_IfHtmlEncodeTrue()
{
// Arrange
var displayFormat = new DisplayFormatAttribute { HtmlEncode = true, };
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = new CachedDataAnnotationsModelMetadata(
provider,
containerType: null,
modelType: typeof(object),
propertyName: null,
attributes: new Attribute[] { displayFormat });
// Act
var result = metadata.DataTypeName;
// Assert
Assert.Null(result);
}
[Fact]
public void DataTypeName_Html_IfHtmlEncodeFalse()
{
// Arrange
var expected = "Html";
var displayFormat = new DisplayFormatAttribute { HtmlEncode = false, };
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = new CachedDataAnnotationsModelMetadata(
provider,
containerType: null,
modelType: typeof(object),
propertyName: null,
attributes: new Attribute[] { displayFormat });
// Act
var result = metadata.DataTypeName;
// Assert
Assert.Equal(expected, result);
}
[Fact]
public void DataTypeName_AttributesHaveExpectedPrecedence()
{
// Arrange
var expected = "MultilineText";
var dataType = new DataTypeAttribute(DataType.MultilineText);
var displayFormat = new DisplayFormatAttribute { HtmlEncode = false, };
var provider = new DataAnnotationsModelMetadataProvider();
var metadata = new CachedDataAnnotationsModelMetadata(
provider,
containerType: null,
modelType: typeof(object),
propertyName: null,
attributes: new Attribute[] { dataType, displayFormat });
// Act
var result = metadata.DataTypeName;
// Assert
Assert.Equal(expected, result);
}
[Fact]
public void DisplayFormatString_AttributesHaveExpectedPrecedence()
{
@ -220,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
containerType: null,
modelType: typeof(object),
propertyName: null,
attributes: new Attribute[] { dataType, displayFormat, });
attributes: new Attribute[] { dataType, displayFormat });
// Act
var result = metadata.DisplayFormatString;
@ -246,7 +312,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
containerType: null,
modelType: typeof(object),
propertyName: null,
attributes: new Attribute[] { dataType, displayFormat, });
attributes: new Attribute[] { dataType, displayFormat });
// Act
var result = metadata.EditFormatString;