Changes to support DisplayColumn attribute. Updating the MvcSample as well to start using DisplayColumn attribute. Adding UnitTests for the same.

This commit is contained in:
sornaks 2014-04-29 11:45:01 -07:00
parent 7396f58d99
commit 28516a0ae9
7 changed files with 156 additions and 1 deletions

View File

@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
namespace MvcSample.Web.Models
{
[DisplayColumn("Name")]
public class User
{
public User()

View File

@ -54,7 +54,7 @@
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more &raquo;</a></p>
</div>
<div class="row">
<h3 title="@Model.Name" class="@nullValue">Hello @Model.Name! Happy @Model.Age birthday.</h3>
<h3 title="@Model.Name" class="@nullValue">Hello @Html.DisplayTextFor(User => User)! Happy @Model.Age birthday.</h3>
<h3 id="qux">This value was retrieved asynchronously: @(await AsyncValueRetrieval())</h3>
<h3>Partial Async: @await Html.PartialAsync("HelloWorldPartial", Model)</h3>
<h3>

View File

@ -14,6 +14,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
{
Display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
DisplayFormat = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault();
DisplayColumn = attributes.OfType<DisplayColumnAttribute>().FirstOrDefault();
Editable = attributes.OfType<EditableAttribute>().FirstOrDefault();
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
}
@ -22,6 +23,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public DisplayFormatAttribute DisplayFormat { get; protected set; }
public DisplayColumnAttribute DisplayColumn { get; protected set; }
public EditableAttribute Editable { get; protected set; }
public RequiredAttribute Required { get; protected set; }

View File

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace Microsoft.AspNet.Mvc.ModelBinding
{
@ -63,6 +65,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return (PrototypeCache.Required != null) || base.ComputeIsRequired();
}
protected override string ComputeSimpleDisplayText()
{
if (Model != null &&
PrototypeCache.DisplayColumn != null &&
!string.IsNullOrEmpty(PrototypeCache.DisplayColumn.DisplayColumn))
{
var displayColumnProperty = ModelType.GetTypeInfo().GetDeclaredProperty(
PrototypeCache.DisplayColumn.DisplayColumn);
ValidateDisplayColumnAttribute(PrototypeCache.DisplayColumn, displayColumnProperty, ModelType);
var simpleDisplayTextValue = displayColumnProperty.GetValue(Model, null);
if (simpleDisplayTextValue != null)
{
return simpleDisplayTextValue.ToString();
}
}
return base.ComputeSimpleDisplayText();
}
public override string GetDisplayName()
{
// DisplayAttribute doesn't require you to set a name, so this could be null.
@ -78,5 +100,23 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// If DisplayAttribute does not specify a name, we'll fall back to the property name.
return base.GetDisplayName();
}
private static void ValidateDisplayColumnAttribute(DisplayColumnAttribute displayColumnAttribute,
PropertyInfo displayColumnProperty, Type modelType)
{
if (displayColumnProperty == null)
{
throw new InvalidOperationException(
Resources.FormatDataAnnotationsModelMetadataProvider_UnknownProperty(
modelType.FullName, displayColumnAttribute.DisplayColumn));
}
if (displayColumnProperty.GetGetMethod() == null)
{
throw new InvalidOperationException(
Resources.FormatDataAnnotationsModelMetadataProvider_UnreadableProperty(
modelType.FullName, displayColumnAttribute.DisplayColumn));
}
}
}
}

View File

@ -378,6 +378,44 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_NoConverterExists"), p0, p1);
}
/// <summary>
/// {0} has a DisplayColumn attribute for {1}, but property {1} does not exist..
/// </summary>
internal static string DataAnnotationsModelMetadataProvider_UnknownProperty
{
get
{
return GetString("DataAnnotationsModelMetadataProvider_UnknownProperty");
}
}
/// <summary>
/// {0} has a DisplayColumn attribute for {1}, but property {1} does not exist..
/// </summary>
internal static string FormatDataAnnotationsModelMetadataProvider_UnknownProperty(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DataAnnotationsModelMetadataProvider_UnknownProperty"), p0, p1);
}
/// <summary>
/// {0} has a DisplayColumn attribute for {1}, but property {1} does not have a public 'get' method..
/// </summary>
internal static string DataAnnotationsModelMetadataProvider_UnreadableProperty
{
get
{
return GetString("DataAnnotationsModelMetadataProvider_UnreadableProperty");
}
}
/// <summary>
/// {0} has a DisplayColumn attribute for {1}, but property {1} does not have a public 'get' method..
/// </summary>
internal static string FormatDataAnnotationsModelMetadataProvider_UnreadableProperty(object p0, object p1)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DataAnnotationsModelMetadataProvider_UnreadableProperty"), p0, p1);
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -186,4 +186,10 @@
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
</data>
<data name="DataAnnotationsModelMetadataProvider_UnknownProperty" xml:space="preserve">
<value>{0} has a DisplayColumn attribute for {1}, but property {1} does not exist.</value>
</data>
<data name="DataAnnotationsModelMetadataProvider_UnreadableProperty" xml:space="preserve">
<value>{0} has a DisplayColumn attribute for {1}, but property {1} does not have a public 'get' method.</value>
</data>
</root>

View File

@ -182,6 +182,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private class Class1
{
public string Prop1 { get; set; }
public override string ToString()
{
return "Class1";
}
}
private class Class2
@ -220,6 +224,69 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
Assert.Equal("Object", result);
}
#endif
// SimpleDisplayText
public static IEnumerable<object[]> SimpleDisplayTextData
{
get
{
yield return new object[]
{
new Func<object>(() => new ComplexClass()
{
Prop1 = new Class1 { Prop1 = "Hello" }
}),
typeof(ComplexClass),
"Class1"
};
yield return new object[]
{
new Func<object>(() => new Class1()),
typeof(Class1),
"Class1"
};
yield return new object[]
{
new Func<object>(() => new ClassWithNoProperties()),
typeof(ClassWithNoProperties),
string.Empty
};
yield return new object[]
{
null,
typeof(object),
null
};
}
}
[Theory]
[MemberData("SimpleDisplayTextData")]
public void TestSimpleDisplayText(Func<object> modelAccessor, Type modelType, string expectedResult)
{
// Arrange
var provider = new EmptyModelMetadataProvider();
var metadata = new ModelMetadata(provider, null, modelAccessor, modelType, null);
// Act
var result = metadata.SimpleDisplayText;
// Assert
Assert.Equal(expectedResult, result);
}
private class ClassWithNoProperties
{
public override string ToString()
{
return null;
}
}
private class ComplexClass
{
public Class1 Prop1 { get; set; }
}
// Helpers