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:
parent
7396f58d99
commit
28516a0ae9
|
|
@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace MvcSample.Web.Models
|
namespace MvcSample.Web.Models
|
||||||
{
|
{
|
||||||
|
[DisplayColumn("Name")]
|
||||||
public class User
|
public class User
|
||||||
{
|
{
|
||||||
public User()
|
public User()
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more »</a></p>
|
<p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more »</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<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 id="qux">This value was retrieved asynchronously: @(await AsyncValueRetrieval())</h3>
|
||||||
<h3>Partial Async: @await Html.PartialAsync("HelloWorldPartial", Model)</h3>
|
<h3>Partial Async: @await Html.PartialAsync("HelloWorldPartial", Model)</h3>
|
||||||
<h3>
|
<h3>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
Display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
|
Display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
|
||||||
DisplayFormat = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault();
|
DisplayFormat = attributes.OfType<DisplayFormatAttribute>().FirstOrDefault();
|
||||||
|
DisplayColumn = attributes.OfType<DisplayColumnAttribute>().FirstOrDefault();
|
||||||
Editable = attributes.OfType<EditableAttribute>().FirstOrDefault();
|
Editable = attributes.OfType<EditableAttribute>().FirstOrDefault();
|
||||||
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
Required = attributes.OfType<RequiredAttribute>().FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +23,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
|
|
||||||
public DisplayFormatAttribute DisplayFormat { get; protected set; }
|
public DisplayFormatAttribute DisplayFormat { get; protected set; }
|
||||||
|
|
||||||
|
public DisplayColumnAttribute DisplayColumn { get; protected set; }
|
||||||
|
|
||||||
public EditableAttribute Editable { get; protected set; }
|
public EditableAttribute Editable { get; protected set; }
|
||||||
|
|
||||||
public RequiredAttribute Required { get; protected set; }
|
public RequiredAttribute Required { get; protected set; }
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.ModelBinding
|
namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
{
|
{
|
||||||
|
|
@ -63,6 +65,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return (PrototypeCache.Required != null) || base.ComputeIsRequired();
|
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()
|
public override string GetDisplayName()
|
||||||
{
|
{
|
||||||
// DisplayAttribute doesn't require you to set a name, so this could be null.
|
// 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.
|
// If DisplayAttribute does not specify a name, we'll fall back to the property name.
|
||||||
return base.GetDisplayName();
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,44 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
return string.Format(CultureInfo.CurrentCulture, GetString("ValueProviderResult_NoConverterExists"), p0, p1);
|
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)
|
private static string GetString(string name, params string[] formatterNames)
|
||||||
{
|
{
|
||||||
var value = _resourceManager.GetString(name);
|
var value = _resourceManager.GetString(name);
|
||||||
|
|
|
||||||
|
|
@ -186,4 +186,10 @@
|
||||||
<data name="ValueProviderResult_NoConverterExists" xml:space="preserve">
|
<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>
|
<value>The parameter conversion from type '{0}' to type '{1}' failed because no type converter can convert between these types.</value>
|
||||||
</data>
|
</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>
|
</root>
|
||||||
|
|
@ -182,6 +182,10 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
private class Class1
|
private class Class1
|
||||||
{
|
{
|
||||||
public string Prop1 { get; set; }
|
public string Prop1 { get; set; }
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "Class1";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Class2
|
private class Class2
|
||||||
|
|
@ -220,6 +224,69 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
||||||
Assert.Equal("Object", result);
|
Assert.Equal("Object", result);
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
// Helpers
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue