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
//
// Order EnumDisplayNamesAndValues to match Enum.GetNames(). That method orders by absolute value,
// then its behavior is undefined (but hopefully stable). Add to EnumNamesAndValues in same order but
// Dictionary does not guarantee order will be preserved.
// Order EnumDisplayNamesAndValues by DisplayAttribute.Order, then by the order of Enum.GetNames().
// That method orders by absolute value, then its behavior is undefined (but hopefully stable).
// Add to EnumNamesAndValues in same order but Dictionary does not guarantee order will be preserved.
var groupedDisplayNamesAndValues = new List<KeyValuePair<EnumGroupAndName, string>>();
var namesAndValues = new Dictionary<string, string>();
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 value = ((Enum)field.GetValue(obj: null)).ToString("d");
@ -193,7 +198,7 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
groupName,
() => GetDisplayName(field, enumLocalizer)),
value));
namesAndValues.Add(name, value);
namesAndValues.Add(field.Name, value);
}
displayMetadata.EnumGroupedDisplayNamesAndValues = groupedDisplayNamesAndValues;

View File

@ -976,6 +976,36 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
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]
public void CreateDisplayMetadata_EnumGroupedDisplayNamesAndValues_NameWithNoIStringLocalizerAndNoResourceType()
{
@ -1318,6 +1348,20 @@ namespace Microsoft.AspNetCore.Mvc.DataAnnotations.Internal
MinusTwo = -2,
}
private enum EnumWithDisplayOrder
{
[Display(Order = 3)]
One,
[Display(Order = 2)]
Two,
[Display(Order = 1)]
Three,
Null,
}
private enum EnumWithDuplicates
{
Zero = 0,