Order enum values by DisplayAttribute.Order

Fixes #4297
This commit is contained in:
Derek Gray 2017-03-22 10:15:01 -05:00 committed by Doug Bunting
parent 6436538068
commit 575fe68b2b
2 changed files with 55 additions and 6 deletions

View File

@ -176,15 +176,20 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
// EnumDisplayNamesAndValues and EnumNamesAndValues // EnumDisplayNamesAndValues and EnumNamesAndValues
// //
// Order EnumDisplayNamesAndValues to match Enum.GetNames(). That method orders by absolute value, // Order EnumDisplayNamesAndValues by DisplayAttribute.Order, then by the order of Enum.GetNames().
// then its behavior is undefined (but hopefully stable). Add to EnumNamesAndValues in same order but // That method orders by absolute value, then its behavior is undefined (but hopefully stable).
// Dictionary does not guarantee order will be preserved. // Add to EnumNamesAndValues in same order but Dictionary does not guarantee order will be preserved.
var groupedDisplayNamesAndValues = new List<KeyValuePair<EnumGroupAndName, string>>(); var groupedDisplayNamesAndValues = new List<KeyValuePair<EnumGroupAndName, string>>();
var namesAndValues = new Dictionary<string, string>(); var namesAndValues = new Dictionary<string, string>();
var enumLocalizer = _stringLocalizerFactory?.Create(underlyingType); var enumLocalizer = _stringLocalizerFactory?.Create(underlyingType);
foreach (var name in Enum.GetNames(underlyingType))
var enumFields = Enum.GetNames(underlyingType)
.Select(name => underlyingType.GetField(name))
.OrderBy(field => field.GetCustomAttribute<DisplayAttribute>(inherit: false)?.GetOrder() ?? 1000);
foreach (var field in enumFields)
{ {
var field = underlyingType.GetField(name);
var groupName = GetDisplayGroup(field); var groupName = GetDisplayGroup(field);
var value = ((Enum)field.GetValue(obj: null)).ToString("d"); var value = ((Enum)field.GetValue(obj: null)).ToString("d");
@ -193,7 +198,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
groupName, groupName,
() => GetDisplayName(field, enumLocalizer)), () => GetDisplayName(field, enumLocalizer)),
value)); value));
namesAndValues.Add(name, value); namesAndValues.Add(field.Name, value);
} }
displayMetadata.EnumGroupedDisplayNamesAndValues = groupedDisplayNamesAndValues; displayMetadata.EnumGroupedDisplayNamesAndValues = groupedDisplayNamesAndValues;

View File

@ -976,6 +976,36 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
KVPEnumGroupAndNameComparer.Instance); KVPEnumGroupAndNameComparer.Instance);
} }
[Fact]
public void CreateDisplayMetadata_EnumGroupedDisplayNamesAndValues_ReflectsDisplayAttributeOrder()
{
// Arrange
var expectedKeyValuePairs = new List<KeyValuePair<EnumGroupAndName, string>>
{
new KeyValuePair<EnumGroupAndName, string>(new EnumGroupAndName(string.Empty, nameof(EnumWithDisplayOrder.Three)), "2"),
new KeyValuePair<EnumGroupAndName, string>(new EnumGroupAndName(string.Empty, nameof(EnumWithDisplayOrder.Two)), "1"),
new KeyValuePair<EnumGroupAndName, string>(new EnumGroupAndName(string.Empty, nameof(EnumWithDisplayOrder.One)), "0"),
new KeyValuePair<EnumGroupAndName, string>(new EnumGroupAndName(string.Empty, nameof(EnumWithDisplayOrder.Null)), "3"),
};
var provider = new DataAnnotationsMetadataProvider(
new TestOptionsManager<MvcDataAnnotationsLocalizationOptions>(),
stringLocalizerFactory: null);
var key = ModelMetadataIdentity.ForType(typeof(EnumWithDisplayOrder));
var attributes = new object[0];
var context = new DisplayMetadataProviderContext(key, new ModelAttributes(attributes));
// Act
provider.CreateDisplayMetadata(context);
// Assert
Assert.Equal(
expectedKeyValuePairs,
context.DisplayMetadata.EnumGroupedDisplayNamesAndValues,
KVPEnumGroupAndNameComparer.Instance);
}
[Fact] [Fact]
public void CreateDisplayMetadata_EnumGroupedDisplayNamesAndValues_NameWithNoIStringLocalizerAndNoResourceType() public void CreateDisplayMetadata_EnumGroupedDisplayNamesAndValues_NameWithNoIStringLocalizerAndNoResourceType()
{ {
@ -1318,6 +1348,20 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
MinusTwo = -2, MinusTwo = -2,
} }
private enum EnumWithDisplayOrder
{
[Display(Order = 3)]
One,
[Display(Order = 2)]
Two,
[Display(Order = 1)]
Three,
Null,
}
private enum EnumWithDuplicates private enum EnumWithDuplicates
{ {
Zero = 0, Zero = 0,