Add `enum`-related details to `ModelMetadata`

- #438 part 1/2 and #2027 part 1/3

slight oddity in the XML docs
- unfortunately Roslyn seems to ignore `TypeInfo` being a subclass of `Type`

nit: use correct `warningsAsErrors` datatype in test project.json
This commit is contained in:
Doug Bunting 2015-03-20 18:26:04 -07:00
parent c62974d39b
commit 7dd3afe3d1
8 changed files with 635 additions and 7 deletions

View File

@ -1,8 +1,11 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
@ -91,6 +94,39 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
displayMetadata.EditFormatString = displayFormatAttribute.DataFormatString;
}
// IsEnum et cetera
var underlyingType = Nullable.GetUnderlyingType(context.Key.ModelType) ?? context.Key.ModelType;
if (underlyingType.IsEnum())
{
// IsEnum
displayMetadata.IsEnum = true;
// IsFlagsEnum
var underlyingTypeInfo = underlyingType.GetTypeInfo();
displayMetadata.IsFlagsEnum =
underlyingTypeInfo.GetCustomAttribute<FlagsAttribute>(inherit: false) != null;
// 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.
var displayNamesAndValues = new List<KeyValuePair<string, string>>();
var namesAndValues = new Dictionary<string, string>();
foreach (var name in Enum.GetNames(underlyingType))
{
var field = underlyingType.GetField(name);
var displayName = GetDisplayName(field);
var value = ((Enum)field.GetValue(obj: null)).ToString("d");
displayNamesAndValues.Add(new KeyValuePair<string, string>(displayName, value));
namesAndValues.Add(name, value);
}
displayMetadata.EnumDisplayNamesAndValues = displayNamesAndValues;
displayMetadata.EnumNamesAndValues = namesAndValues;
}
// HasNonDefaultEditFormat
if (!string.IsNullOrEmpty(displayFormatAttribute?.DataFormatString) &&
displayFormatAttribute?.ApplyFormatInEditMode == true)
@ -139,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
displayMetadata.Order = displayAttribute.GetOrder().Value;
}
// ShowForDisplay
// ShowForDisplay
if (scaffoldColumnAttribute != null)
{
displayMetadata.ShowForDisplay = scaffoldColumnAttribute.Scaffold;
@ -157,7 +193,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
displayMetadata.SimpleDisplayProperty = displayColumnAttribute.DisplayColumn;
}
// TemplateHinte
// TemplateHint
if (uiHintAttribute != null)
{
displayMetadata.TemplateHint = uiHintAttribute.UIHint;
@ -176,5 +212,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
context.ValidationMetadata.ValiatorMetadata.Add(attribute);
}
}
// Return non-empty name specified in a [Display] attribute for a field, if any; field.Name otherwise.
private static string GetDisplayName(FieldInfo field)
{
var display = field.GetCustomAttribute<DisplayAttribute>(inherit: false);
if (display != null)
{
var name = display.GetName();
if (!string.IsNullOrEmpty(name))
{
return name;
}
}
return field.Name;
}
}
}

View File

@ -210,6 +210,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
}
}
/// <inheritdoc />
public override IEnumerable<KeyValuePair<string, string>> EnumDisplayNamesAndValues
{
get
{
return DisplayMetadata.EnumDisplayNamesAndValues;
}
}
/// <inheritdoc />
public override IReadOnlyDictionary<string, string> EnumNamesAndValues
{
get
{
return DisplayMetadata.EnumNamesAndValues;
}
}
/// <inheritdoc />
public override bool HasNonDefaultEditFormat
{
@ -237,6 +255,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
}
}
/// <inheritdoc />
public override bool IsEnum
{
get
{
return DisplayMetadata.IsEnum;
}
}
/// <inheritdoc />
public override bool IsFlagsEnum
{
get
{
return DisplayMetadata.IsFlagsEnum;
}
}
/// <inheritdoc />
public override bool IsReadOnly
{
@ -274,7 +310,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
_isRequired = !ModelType.AllowsNullValue();
}
}
return _isRequired.Value;
}
}

View File

@ -55,6 +55,20 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
/// </remarks>
public string EditFormatString { get; set; }
/// <summary>
/// Gets the ordered display names and values of all <see cref="System.Enum"/> values in
/// <see cref="ModelMetadata.ModelType"/> or <c>Nullable.GetUnderlyingType(ModelType)</c>. See
/// <see cref="ModelMetadata.EnumDisplayNamesAndValues"/>.
/// </summary>
public IEnumerable<KeyValuePair<string, string>> EnumDisplayNamesAndValues { get; set; }
/// <summary>
/// Gets the names and values of all <see cref="System.Enum"/> values in <see cref="ModelMetadata.ModelType"/>
/// or <c>Nullable.GetUnderlyingType(ModelType)</c>. See <see cref="ModelMetadata.EnumNamesAndValues"/>.
/// </summary>
// This could be implemented in DefaultModelMetadata. But value should be cached.
public IReadOnlyDictionary<string, string> EnumNamesAndValues { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not the model has a non-default edit format.
/// See <see cref="ModelMetadata.HasNonDefaultEditFormat"/>
@ -73,6 +87,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
/// </summary>
public bool HtmlEncode { get; set; } = true;
/// <summary>
/// Gets a value indicating whether <see cref="ModelMetadata.ModelType"/> or
/// <c>Nullable.GetUnderlyingType(ModelType)</c> is for an <see cref="System.Enum"/>. See
/// <see cref="ModelMetadata.IsEnum"/>.
/// </summary>
// This could be implemented in DefaultModelMetadata. But value is needed in the details provider.
public bool IsEnum { get; set; }
/// <summary>
/// Gets a value indicating whether <see cref="ModelMetadata.ModelType"/> or
/// <c>Nullable.GetUnderlyingType(ModelType)</c> is for an <see cref="System.Enum"/> with an associated
/// <see cref="System.FlagsAttribute"/>. See <see cref="ModelMetadata.IsFlagsEnum"/>.
/// </summary>
// This could be implemented in DefaultModelMetadata. But value is needed in the details provider.
public bool IsFlagsEnum { get; set; }
/// <summary>
/// Gets or sets the text to display when the model value is null.
/// See <see cref="ModelMetadata.NullDisplayText"/>

View File

@ -120,6 +120,26 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </summary>
public abstract string EditFormatString { get; }
/// <summary>
/// Gets the ordered display names and values of all <see cref="Enum"/> values in <see cref="ModelType"/> or
/// <c>Nullable.GetUnderlyingType(ModelType)</c>.
/// </summary>
/// <value>
/// An <see cref="IEnumerable{KeyValuePair{string, string}}"/> of mappings between <see cref="Enum"/> field names
/// and values. <c>null</c> if <see cref="IsEnum"/> is <c>false</c>.
/// </value>
public abstract IEnumerable<KeyValuePair<string, string>> EnumDisplayNamesAndValues { get; }
/// <summary>
/// Gets the names and values of all <see cref="Enum"/> values in <see cref="ModelType"/> or
/// <c>Nullable.GetUnderlyingType(ModelType)</c>.
/// </summary>
/// <value>
/// An <see cref="IReadOnlyDictionary{string, string}"/> of mappings between <see cref="Enum"/> field names
/// and values. <c>null</c> if <see cref="IsEnum"/> is <c>false</c>.
/// </value>
public abstract IReadOnlyDictionary<string, string> EnumNamesAndValues { get; }
/// <summary>
/// Gets a value indicating whether <see cref="EditFormatString"/> has a non-<c>null</c>, non-empty
/// value different from the default for the datatype.
@ -145,6 +165,27 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
/// </remarks>
public abstract bool HideSurroundingHtml { get; }
/// <summary>
/// Gets a value indicating whether <see cref="ModelType"/> or <c>Nullable.GetUnderlyingType(ModelType)</c> is
/// for an <see cref="Enum"/>.
/// </summary>
/// <value>
/// <c>true</c> if <c>type.IsEnum</c> (<c>type.GetTypeInfo().IsEnum</c> for DNX Core 5.0) is <c>true</c> for
/// <see cref="ModelType"/> or <c>Nullable.GetUnderlyingType(ModelType)</c>; <c>false</c> otherwise.
/// </value>
public abstract bool IsEnum { get; }
/// <summary>
/// Gets a value indicating whether <see cref="ModelType"/> or <c>Nullable.GetUnderlyingType(ModelType)</c> is
/// for an <see cref="Enum"/> with an associated <see cref="FlagsAttribute"/>.
/// </summary>
/// <value>
/// <c>true</c> if <see cref="IsEnum"/> is <c>true</c> and <see cref="ModelType"/> or
/// <c>Nullable.GetUnderlyingType(ModelType)</c> has an associated <see cref="FlagsAttribute"/>; <c>false</c>
/// otherwise.
/// </value>
public abstract bool IsFlagsEnum { get; }
/// <summary>
/// Gets a value indicating whether or not the model value is read-only. This is only applicable when
/// the current instance represents a property.

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Xunit;
@ -9,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
{
public class DataAnnotationsMetadataProviderTest
{
// Includes attributes with a 'simple' effect on display details.
// Includes attributes with a 'simple' effect on display details.
public static TheoryData<object, Func<DisplayMetadata, object>, object> DisplayDetailsData
{
get
@ -47,8 +48,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
[Theory]
[MemberData(nameof(DisplayDetailsData))]
public void GetDisplayDetails_SimpleAttributes(
object attribute,
Func<DisplayMetadata, object> accessor,
object attribute,
Func<DisplayMetadata, object> accessor,
object expected)
{
// Arrange
@ -193,5 +194,437 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
// Assert
Assert.Equal("description from resources", context.DisplayMetadata.Description);
}
[Theory]
[InlineData(typeof(EmptyClass), false)]
[InlineData(typeof(ClassWithFields), false)]
[InlineData(typeof(ClassWithProperties), false)]
[InlineData(typeof(EmptyEnum), true)]
[InlineData(typeof(EmptyEnum?), true)]
[InlineData(typeof(EnumWithDisplayNames), true)]
[InlineData(typeof(EnumWithDisplayNames?), true)]
[InlineData(typeof(EnumWithDuplicates), true)]
[InlineData(typeof(EnumWithDuplicates?), true)]
[InlineData(typeof(EnumWithFlags), true)]
[InlineData(typeof(EnumWithFlags?), true)]
[InlineData(typeof(EnumWithFields), true)]
[InlineData(typeof(EnumWithFields?), true)]
[InlineData(typeof(EmptyStruct), false)]
[InlineData(typeof(StructWithFields), false)]
[InlineData(typeof(StructWithFields?), false)]
[InlineData(typeof(StructWithProperties), false)]
public void GetDisplayDetails_IsEnum_ReflectsModelType(Type type, bool expectedIsEnum)
{
// Arrange
var provider = new DataAnnotationsMetadataProvider();
var key = ModelMetadataIdentity.ForType(type);
var attributes = new object[0];
var context = new DisplayMetadataProviderContext(key, attributes);
// Act
provider.GetDisplayMetadata(context);
// Assert
Assert.Equal(expectedIsEnum, context.DisplayMetadata.IsEnum);
}
[Theory]
[InlineData(typeof(EmptyClass), false)]
[InlineData(typeof(ClassWithFields), false)]
[InlineData(typeof(ClassWithProperties), false)]
[InlineData(typeof(EmptyEnum), false)]
[InlineData(typeof(EmptyEnum?), false)]
[InlineData(typeof(EnumWithDisplayNames), false)]
[InlineData(typeof(EnumWithDisplayNames?), false)]
[InlineData(typeof(EnumWithDuplicates), false)]
[InlineData(typeof(EnumWithDuplicates?), false)]
[InlineData(typeof(EnumWithFlags), true)]
[InlineData(typeof(EnumWithFlags?), true)]
[InlineData(typeof(EnumWithFields), false)]
[InlineData(typeof(EnumWithFields?), false)]
[InlineData(typeof(EmptyStruct), false)]
[InlineData(typeof(StructWithFields), false)]
[InlineData(typeof(StructWithFields?), false)]
[InlineData(typeof(StructWithProperties), false)]
public void GetDisplayDetails_IsFlagsEnum_ReflectsModelType(Type type, bool expectedIsFlagsEnum)
{
// Arrange
var provider = new DataAnnotationsMetadataProvider();
var key = ModelMetadataIdentity.ForType(type);
var attributes = new object[0];
var context = new DisplayMetadataProviderContext(key, attributes);
// Act
provider.GetDisplayMetadata(context);
// Assert
Assert.Equal(expectedIsFlagsEnum, context.DisplayMetadata.IsFlagsEnum);
}
// Type -> expected EnumNamesAndValues
public static TheoryData<Type, IReadOnlyDictionary<string, string>> EnumNamesData
{
get
{
return new TheoryData<Type, IReadOnlyDictionary<string, string>>
{
{ typeof(ClassWithFields), null },
{ typeof(StructWithFields), null },
{ typeof(StructWithFields?), null },
{ typeof(EmptyEnum), new Dictionary<string, string>() },
{ typeof(EmptyEnum?), new Dictionary<string, string>() },
{
typeof(EnumWithDisplayNames),
new Dictionary<string, string>
{
{ nameof(EnumWithDisplayNames.MinusTwo), "-2" },
{ nameof(EnumWithDisplayNames.MinusOne), "-1" },
{ nameof(EnumWithDisplayNames.Zero), "0" },
{ nameof(EnumWithDisplayNames.One), "1" },
{ nameof(EnumWithDisplayNames.Two), "2" },
{ nameof(EnumWithDisplayNames.Three), "3" },
}
},
{
typeof(EnumWithDisplayNames?),
new Dictionary<string, string>
{
{ nameof(EnumWithDisplayNames.MinusTwo), "-2" },
{ nameof(EnumWithDisplayNames.MinusOne), "-1" },
{ nameof(EnumWithDisplayNames.Zero), "0" },
{ nameof(EnumWithDisplayNames.One), "1" },
{ nameof(EnumWithDisplayNames.Two), "2" },
{ nameof(EnumWithDisplayNames.Three), "3" },
}
},
{
typeof(EnumWithDuplicates),
new Dictionary<string, string>
{
{ nameof(EnumWithDuplicates.Zero), "0" },
{ nameof(EnumWithDuplicates.None), "0" },
{ nameof(EnumWithDuplicates.One), "1" },
{ nameof(EnumWithDuplicates.Two), "2" },
{ nameof(EnumWithDuplicates.Duece), "2" },
{ nameof(EnumWithDuplicates.Three), "3" },
{ nameof(EnumWithDuplicates.MoreThanTwo), "3" },
}
},
{
typeof(EnumWithDuplicates?),
new Dictionary<string, string>
{
{ nameof(EnumWithDuplicates.Zero), "0" },
{ nameof(EnumWithDuplicates.None), "0" },
{ nameof(EnumWithDuplicates.One), "1" },
{ nameof(EnumWithDuplicates.Two), "2" },
{ nameof(EnumWithDuplicates.Duece), "2" },
{ nameof(EnumWithDuplicates.Three), "3" },
{ nameof(EnumWithDuplicates.MoreThanTwo), "3" },
}
},
{
typeof(EnumWithFlags),
new Dictionary<string, string>
{
{ nameof(EnumWithFlags.All), "-1" },
{ nameof(EnumWithFlags.Zero), "0" },
{ nameof(EnumWithFlags.One), "1" },
{ nameof(EnumWithFlags.Two), "2" },
{ nameof(EnumWithFlags.Four), "4" },
}
},
{
typeof(EnumWithFlags?),
new Dictionary<string, string>
{
{ nameof(EnumWithFlags.All), "-1" },
{ nameof(EnumWithFlags.Zero), "0" },
{ nameof(EnumWithFlags.One), "1" },
{ nameof(EnumWithFlags.Two), "2" },
{ nameof(EnumWithFlags.Four), "4" },
}
},
{
typeof(EnumWithFields),
new Dictionary<string, string>
{
{ nameof(EnumWithFields.MinusTwo), "-2" },
{ nameof(EnumWithFields.MinusOne), "-1" },
{ nameof(EnumWithFields.Zero), "0" },
{ nameof(EnumWithFields.One), "1" },
{ nameof(EnumWithFields.Two), "2" },
{ nameof(EnumWithFields.Three), "3" },
}
},
{
typeof(EnumWithFields?),
new Dictionary<string, string>
{
{ nameof(EnumWithFields.MinusTwo), "-2" },
{ nameof(EnumWithFields.MinusOne), "-1" },
{ nameof(EnumWithFields.Zero), "0" },
{ nameof(EnumWithFields.One), "1" },
{ nameof(EnumWithFields.Two), "2" },
{ nameof(EnumWithFields.Three), "3" },
}
},
};
}
}
[Theory]
[MemberData(nameof(EnumNamesData))]
public void GetDisplayDetails_EnumNamesAndValues_ReflectsModelType(
Type type,
IReadOnlyDictionary<string, string> expectedDictionary)
{
// Arrange
var provider = new DataAnnotationsMetadataProvider();
var key = ModelMetadataIdentity.ForType(type);
var attributes = new object[0];
var context = new DisplayMetadataProviderContext(key, attributes);
// Act
provider.GetDisplayMetadata(context);
// Assert
// This assertion does *not* require entry orders to match.
Assert.Equal(expectedDictionary, context.DisplayMetadata.EnumNamesAndValues);
}
// Type -> expected EnumDisplayNamesAndValues
public static TheoryData<Type, IEnumerable<KeyValuePair<string, string>>> EnumDisplayNamesData
{
get
{
return new TheoryData<Type, IEnumerable<KeyValuePair<string, string>>>
{
{ typeof(ClassWithFields), null },
{ typeof(StructWithFields), null },
{ typeof(EmptyEnum), new List<KeyValuePair<string, string>>() },
{ typeof(EmptyEnum?), new List<KeyValuePair<string, string>>() },
{
typeof(EnumWithDisplayNames),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("cero", "0"),
new KeyValuePair<string, string>("uno", "1"),
new KeyValuePair<string, string>("dos", "2"),
new KeyValuePair<string, string>("tres", "3"),
new KeyValuePair<string, string>("name from resources", "-2"),
new KeyValuePair<string, string>("menos uno", "-1"),
}
},
{
typeof(EnumWithDisplayNames?),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("cero", "0"),
new KeyValuePair<string, string>("uno", "1"),
new KeyValuePair<string, string>("dos", "2"),
new KeyValuePair<string, string>("tres", "3"),
new KeyValuePair<string, string>("name from resources", "-2"),
new KeyValuePair<string, string>("menos uno", "-1"),
}
},
{
// Note order duplicates appear cannot be inferred easily e.g. does not match the source.
// Zero is before None but Two is before Duece in the class below.
typeof(EnumWithDuplicates),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Zero), "0"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.None), "0"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.One), "1"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Duece), "2"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Two), "2"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.MoreThanTwo), "3"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Three), "3"),
}
},
{
typeof(EnumWithDuplicates?),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Zero), "0"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.None), "0"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.One), "1"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Duece), "2"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Two), "2"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.MoreThanTwo), "3"),
new KeyValuePair<string, string>(nameof(EnumWithDuplicates.Three), "3"),
}
},
{
typeof(EnumWithFlags),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(nameof(EnumWithFlags.Zero), "0"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.One), "1"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.Two), "2"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.Four), "4"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.All), "-1"),
}
},
{
typeof(EnumWithFlags?),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(nameof(EnumWithFlags.Zero), "0"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.One), "1"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.Two), "2"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.Four), "4"),
new KeyValuePair<string, string>(nameof(EnumWithFlags.All), "-1"),
}
},
{
typeof(EnumWithFields),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(nameof(EnumWithFields.Zero), "0"),
new KeyValuePair<string, string>(nameof(EnumWithFields.One), "1"),
new KeyValuePair<string, string>(nameof(EnumWithFields.Two), "2"),
new KeyValuePair<string, string>(nameof(EnumWithFields.Three), "3"),
new KeyValuePair<string, string>(nameof(EnumWithFields.MinusTwo), "-2"),
new KeyValuePair<string, string>(nameof(EnumWithFields.MinusOne), "-1"),
}
},
{
typeof(EnumWithFields?),
new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(nameof(EnumWithFields.Zero), "0"),
new KeyValuePair<string, string>(nameof(EnumWithFields.One), "1"),
new KeyValuePair<string, string>(nameof(EnumWithFields.Two), "2"),
new KeyValuePair<string, string>(nameof(EnumWithFields.Three), "3"),
new KeyValuePair<string, string>(nameof(EnumWithFields.MinusTwo), "-2"),
new KeyValuePair<string, string>(nameof(EnumWithFields.MinusOne), "-1"),
}
},
};
}
}
[Theory]
[MemberData(nameof(EnumDisplayNamesData))]
public void GetDisplayDetails_EnumDisplayNamesAndValues_ReflectsModelType(
Type type,
IEnumerable<KeyValuePair<string, string>> expectedKeyValuePairs)
{
// Arrange
var provider = new DataAnnotationsMetadataProvider();
var key = ModelMetadataIdentity.ForType(type);
var attributes = new object[0];
var context = new DisplayMetadataProviderContext(key, attributes);
// Act
provider.GetDisplayMetadata(context);
// Assert
Assert.Equal(expectedKeyValuePairs, context.DisplayMetadata.EnumDisplayNamesAndValues);
}
private class EmptyClass
{
}
private class ClassWithFields
{
public const int Zero = 0;
public const int One = 1;
}
private class ClassWithProperties
{
public int Id { get; set; }
public string Name { get; set; }
}
private enum EmptyEnum
{
}
private enum EnumWithDisplayNames
{
[Display(Name = "tres")]
Three = 3,
[Display(Name = "dos")]
Two = 2,
[Display(Name = "uno")]
One = 1,
[Display(Name = "cero")]
Zero = 0,
[Display(Name = "menos uno")]
MinusOne = -1,
[Display(Name = nameof(Test.TestResources.DisplayAttribute_Name), ResourceType = typeof(Test.TestResources))]
MinusTwo = -2,
}
private enum EnumWithDuplicates
{
Zero = 0,
One = 1,
Three = 3,
MoreThanTwo = 3,
Two = 2,
None = 0,
Duece = 2,
}
[Flags]
private enum EnumWithFlags
{
Four = 4,
Two = 2,
One = 1,
Zero = 0,
All = -1,
}
private enum EnumWithFields
{
MinusTwo = -2,
MinusOne = -1,
Three = 3,
Two = 2,
One = 1,
Zero = 0,
}
private struct EmptyStruct
{
}
private struct StructWithFields
{
public const int Zero = 0;
public const int One = 1;
}
private struct StructWithProperties
{
public StructWithProperties(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
}
}
}

View File

@ -39,6 +39,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
Assert.True(metadata.HtmlEncode);
Assert.False(metadata.IsComplexType);
Assert.False(metadata.IsCollectionType);
Assert.False(metadata.IsEnum);
Assert.False(metadata.IsFlagsEnum);
Assert.False(metadata.IsNullableValueType);
Assert.False(metadata.IsReadOnly);
Assert.False(metadata.IsRequired);
@ -50,6 +52,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata
Assert.Null(metadata.DisplayFormatString);
Assert.Null(metadata.DisplayName);
Assert.Null(metadata.EditFormatString);
Assert.Null(metadata.EnumDisplayNamesAndValues);
Assert.Null(metadata.EnumNamesAndValues);
Assert.Null(metadata.NullDisplayText);
Assert.Null(metadata.TemplateHint);
Assert.Null(metadata.SimpleDisplayProperty);

View File

@ -269,6 +269,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
}
public override IEnumerable<KeyValuePair<string, string>> EnumDisplayNamesAndValues
{
get
{
throw new NotImplementedException();
}
}
public override IReadOnlyDictionary<string, string> EnumNamesAndValues
{
get
{
throw new NotImplementedException();
}
}
public override bool HasNonDefaultEditFormat
{
get
@ -293,6 +309,22 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
}
public override bool IsEnum
{
get
{
throw new NotImplementedException();
}
}
public override bool IsFlagsEnum
{
get
{
throw new NotImplementedException();
}
}
public override bool IsReadOnly
{
get

View File

@ -1,6 +1,6 @@
{
"compilationOptions": {
"warningsAsErrors": "true"
"warningsAsErrors": true
},
"dependencies": {
"Microsoft.AspNet.FileProviders": "1.0.0-*",