From 3f6ab3bb03c3f38360555e0d9f062d59670e2654 Mon Sep 17 00:00:00 2001 From: Doug Bunting Date: Wed, 10 Jun 2015 12:02:50 -0700 Subject: [PATCH] Add `ModelMetadata.ElementMetadata` - #2664 - use new property to correctly determine `isTargetEnum` in `GetCurrentValues()` - avoid `ArgumentNullException` in all cases where raw values are `enum` but target is not - stop skipping tests blocked by #2664, exposing a couple more #1487 issues - use new property instead of private `GetElementType()` methods where possible - cleans up some duplicate code - also remove redundant use of `IsCollectionType` and `ElementMetadata` nits: - move properties above methods in `ModelMetadata` - avoid accidentally-incorrect "Remove Unnecessary Usings" --- .../ModelBinding/ModelMetadata.cs | 36 +++++++--- .../Metadata/DefaultModelMetadata.cs | 50 ++++++++++++++ .../Validation/DefaultObjectValidator.cs | 31 ++------- .../ModelBindingHelper.cs | 31 ++------- .../Rendering/Html/DefaultDisplayTemplates.cs | 33 +++++---- .../Rendering/Html/DefaultEditorTemplates.cs | 32 +++++---- .../Rendering/Html/DefaultHtmlGenerator.cs | 35 +++++++--- .../ModelBinding/ModelMetadataTest.cs | 8 +++ .../Metadata/DefaultModelMetadataTest.cs | 68 ++++++++++++++++++- .../Rendering/HtmlHelperSelectTest.cs | 10 +-- 10 files changed, 224 insertions(+), 110 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs index e246d2d91c..43c21af51e 100644 --- a/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs +++ b/src/Microsoft.AspNet.Mvc.Abstractions/ModelBinding/ModelMetadata.cs @@ -5,7 +5,9 @@ using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; +#if DNXCORE50 using System.Reflection; +#endif using Microsoft.AspNet.Mvc.ModelBinding.Metadata; using Microsoft.Framework.Internal; @@ -79,7 +81,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding public abstract string BinderModelName { get; } /// - /// Gets the of an of a model if specified explicitly using + /// Gets the of an of a model if specified explicitly using /// . /// public abstract Type BinderType { get; } @@ -124,6 +126,18 @@ namespace Microsoft.AspNet.Mvc.ModelBinding /// public abstract string EditFormatString { get; } + /// + /// Gets the for elements of if that + /// implements . + /// + /// + /// for T if implements + /// . for object if + /// implements but not . null otherwise i.e. when + /// is false. + /// + public abstract ModelMetadata ElementMetadata { get; } + /// /// Gets the ordered display names and values of all values in or /// Nullable.GetUnderlyingType(ModelType). @@ -329,6 +343,16 @@ namespace Microsoft.AspNet.Mvc.ModelBinding } } + /// + /// Gets a property getter delegate to get the property value from a model object. + /// + public abstract Func PropertyGetter { get; } + + /// + /// Gets a property setter delegate to set the property value on a model object. + /// + public abstract Action PropertySetter { get; } + /// /// Gets a display name for the model. /// @@ -341,15 +365,5 @@ namespace Microsoft.AspNet.Mvc.ModelBinding { return DisplayName ?? PropertyName ?? ModelType.Name; } - - /// - /// Gets or sets a property getter delegate to get the property value from a model object. - /// - public abstract Func PropertyGetter { get; } - - /// - /// Gets or sets a property setter delegate to set the property value on a model object. - /// - public abstract Action PropertySetter { get; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs index fe0f44204a..24beb39bb1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Metadata/DefaultModelMetadata.cs @@ -2,9 +2,14 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics; using System.Linq; +#if DNXCORE50 +using System.Reflection; +#endif using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata @@ -19,6 +24,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata private readonly DefaultMetadataDetails _details; private ReadOnlyDictionary _additionalValues; + private ModelMetadata _elementMetadata; + private bool _haveCalculatedElementMetadata; private bool? _isReadOnly; private bool? _isRequired; private ModelPropertyCollection _properties; @@ -220,6 +227,49 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata } } + /// + public override ModelMetadata ElementMetadata + { + get + { + if (!_haveCalculatedElementMetadata) + { + _haveCalculatedElementMetadata = true; + if (!IsCollectionType) + { + // Short-circuit checks below. If not IsCollectionType, ElementMetadata is null. + // For example, as in IsCollectionType, do not consider strings collections. + return null; + } + + Type elementType = null; + if (ModelType.IsArray) + { + elementType = ModelType.GetElementType(); + } + else + { + elementType = ClosedGenericMatcher.ExtractGenericInterface(ModelType, typeof(IEnumerable<>)) + ?.GenericTypeArguments[0]; + if (elementType == null && typeof(IEnumerable).IsAssignableFrom(ModelType)) + { + // ModelType implements IEnumerable but not IEnumerable. + elementType = typeof(object); + } + } + + Debug.Assert( + elementType != null, + $"Unable to find element type for '{ ModelType.FullName }' though IsCollectionType is true."); + + // Success + _elementMetadata = _provider.GetMetadataForType(elementType); + } + + return _elementMetadata; + } + } + /// public override IEnumerable> EnumDisplayNamesAndValues { diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs index 558bae6f3e..21865ef5cd 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBinding/Validation/DefaultObjectValidator.cs @@ -169,11 +169,9 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation ExpandValidationNode(validationContext, modelExplorer); IList validators = null; - if (modelExplorer.Metadata.IsCollectionType && modelExplorer.Model != null) + var elementMetadata = modelExplorer.Metadata.ElementMetadata; + if (elementMetadata != null) { - var enumerableModel = (IEnumerable)modelExplorer.Model; - var elementType = GetElementType(enumerableModel.GetType()); - var elementMetadata = _modelMetadataProvider.GetMetadataForType(elementType); validators = GetValidators(validationContext.ModelValidationContext.ValidatorProvider, elementMetadata); } @@ -283,7 +281,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation return; } - if (!modelExplorer.Metadata.IsCollectionType) + var elementMetadata = modelExplorer.Metadata.ElementMetadata; + if (elementMetadata == null) { foreach (var property in validationNode.ModelMetadata.Properties) { @@ -300,8 +299,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation else { var enumerableModel = (IEnumerable)modelExplorer.Model; - var elementType = GetElementType(enumerableModel.GetType()); - var elementMetadata = _modelMetadataProvider.GetMetadataForType(elementType); // An integer index is incorrect in scenarios where there is a custom index provided by the user. // However those scenarios are supported by createing a ModelValidationNode with the right keys. @@ -321,26 +318,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Validation } } - private static Type GetElementType(Type type) - { - Debug.Assert(typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())); - if (type.IsArray) - { - return type.GetElementType(); - } - - foreach (var implementedInterface in type.GetInterfaces()) - { - if (implementedInterface.GetTypeInfo().IsGenericType && - implementedInterface.GetGenericTypeDefinition() == typeof(IEnumerable<>)) - { - return implementedInterface.GetGenericArguments()[0]; - } - } - - return typeof(object); - } - private class ValidationContext { public ModelValidationContext ModelValidationContext { get; set; } diff --git a/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs b/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs index f56a66513d..8deb7d4947 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ModelBindingHelper.cs @@ -369,7 +369,7 @@ namespace Microsoft.AspNet.Mvc /// Expressions identifying the properties to allow for binding. /// An expression which can be used with . public static Expression> GetIncludePredicateExpression( - string prefix, + string prefix, Expression>[] expressions) { if (expressions.Length == 0) @@ -417,15 +417,15 @@ namespace Microsoft.AspNet.Mvc { // If modelkey is empty, we need to iterate through properties (obtained from ModelMetadata) and // clear validation state for all entries in ModelStateDictionary that start with each property name. - // If modelkey is non-empty, clear validation state for all entries in ModelStateDictionary + // If modelkey is non-empty, clear validation state for all entries in ModelStateDictionary // that start with modelKey if (string.IsNullOrEmpty(modelKey)) { var modelMetadata = metadataProvider.GetMetadataForType(modelType); - if (modelMetadata.IsCollectionType) + var elementMetadata = modelMetadata.ElementMetadata; + if (elementMetadata != null) { - var elementType = GetElementType(modelMetadata.ModelType); - modelMetadata = metadataProvider.GetMetadataForType(elementType); + modelMetadata = elementMetadata; } foreach (var property in modelMetadata.Properties) @@ -440,27 +440,6 @@ namespace Microsoft.AspNet.Mvc } } - private static Type GetElementType(Type type) - { - Debug.Assert(typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(type.GetTypeInfo())); - if (type.IsArray) - { - return type.GetElementType(); - } - - foreach (var implementedInterface in type.GetInterfaces()) - { - if (implementedInterface.GetTypeInfo().IsGenericType && - implementedInterface.GetGenericTypeDefinition() == typeof(IEnumerable<>)) - { - return implementedInterface.GetGenericArguments()[0]; - } - } - - return typeof(object); - } - - internal static void ValidateBindingContext([NotNull] ModelBindingContext bindingContext) { if (bindingContext.ModelMetadata == null) diff --git a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultDisplayTemplates.cs b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultDisplayTemplates.cs index c2c28877f2..799c547d4a 100644 --- a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultDisplayTemplates.cs +++ b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultDisplayTemplates.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Text; using Microsoft.AspNet.Mvc.Extensions; @@ -106,40 +107,42 @@ namespace Microsoft.AspNet.Mvc.Rendering "Collection", model.GetType().FullName, typeof(IEnumerable).FullName)); } - var typeInCollection = typeof(string); - var genericEnumerableType = ClosedGenericMatcher.ExtractGenericInterface( - collection.GetType(), - typeof(IEnumerable<>)); - if (genericEnumerableType != null) + var elementMetadata = htmlHelper.ViewData.ModelMetadata.ElementMetadata; + Debug.Assert(elementMetadata != null); + var typeInCollectionIsNullableValueType = elementMetadata.IsNullableValueType; + + var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices; + var metadataProvider = serviceProvider.GetRequiredService(); + + // Use typeof(string) instead of typeof(object) for IEnumerable collections. Neither type is Nullable. + if (elementMetadata.ModelType == typeof(object)) { - typeInCollection = genericEnumerableType.GenericTypeArguments[0]; + elementMetadata = metadataProvider.GetMetadataForType(typeof(string)); } - var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection); - var oldPrefix = htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix; - try { htmlHelper.ViewData.TemplateInfo.HtmlFieldPrefix = string.Empty; var fieldNameBase = oldPrefix; var result = new StringBuilder(); - - var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices; - var metadataProvider = serviceProvider.GetRequiredService(); var viewEngine = serviceProvider.GetRequiredService(); var index = 0; foreach (var item in collection) { - var itemType = typeInCollection; + var itemMetadata = elementMetadata; if (item != null && !typeInCollectionIsNullableValueType) { - itemType = item.GetType(); + itemMetadata = metadataProvider.GetMetadataForType(item.GetType()); } - var modelExplorer = metadataProvider.GetModelExplorerForType(itemType, item); + var modelExplorer = new ModelExplorer( + metadataProvider, + container: htmlHelper.ViewData.ModelExplorer, + metadata: itemMetadata, + model: item); var fieldName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++); var templateBuilder = new TemplateBuilder( diff --git a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultEditorTemplates.cs b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultEditorTemplates.cs index c06eb66bed..0056471392 100644 --- a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultEditorTemplates.cs +++ b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultEditorTemplates.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.Text; using Microsoft.AspNet.Mvc.Extensions; @@ -67,39 +68,42 @@ namespace Microsoft.AspNet.Mvc.Rendering "Collection", model.GetType().FullName, typeof(IEnumerable).FullName)); } - var typeInCollection = typeof(string); - var genericEnumerableType = ClosedGenericMatcher.ExtractGenericInterface( - collection.GetType(), - typeof(IEnumerable<>)); - if (genericEnumerableType != null) + var elementMetadata = htmlHelper.ViewData.ModelMetadata.ElementMetadata; + Debug.Assert(elementMetadata != null); + var typeInCollectionIsNullableValueType = elementMetadata.IsNullableValueType; + + var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices; + var metadataProvider = serviceProvider.GetRequiredService(); + + // Use typeof(string) instead of typeof(object) for IEnumerable collections. Neither type is Nullable. + if (elementMetadata.ModelType == typeof(object)) { - typeInCollection = genericEnumerableType.GenericTypeArguments[0]; + elementMetadata = metadataProvider.GetMetadataForType(typeof(string)); } - var typeInCollectionIsNullableValueType = TypeHelper.IsNullableValueType(typeInCollection); var oldPrefix = viewData.TemplateInfo.HtmlFieldPrefix; - try { viewData.TemplateInfo.HtmlFieldPrefix = string.Empty; var fieldNameBase = oldPrefix; var result = new StringBuilder(); - - var serviceProvider = htmlHelper.ViewContext.HttpContext.RequestServices; - var metadataProvider = serviceProvider.GetRequiredService(); var viewEngine = serviceProvider.GetRequiredService(); var index = 0; foreach (var item in collection) { - var itemType = typeInCollection; + var itemMetadata = elementMetadata; if (item != null && !typeInCollectionIsNullableValueType) { - itemType = item.GetType(); + itemMetadata = metadataProvider.GetMetadataForType(item.GetType()); } - var modelExplorer = metadataProvider.GetModelExplorerForType(itemType, item); + var modelExplorer = new ModelExplorer( + metadataProvider, + container: htmlHelper.ViewData.ModelExplorer, + metadata: itemMetadata, + model: item); var fieldName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++); var templateBuilder = new TemplateBuilder( diff --git a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultHtmlGenerator.cs index 1a4f086da7..bebf163fdc 100644 --- a/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultHtmlGenerator.cs +++ b/src/Microsoft.AspNet.Mvc.Extensions/Rendering/Html/DefaultHtmlGenerator.cs @@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.Rendering /// /// Initializes a new instance of the class. /// - /// The instance which is used to generate anti-forgery + /// The instance which is used to generate anti-forgery /// tokens. /// The accessor for . /// The . @@ -796,11 +796,19 @@ namespace Microsoft.AspNet.Mvc.Rendering modelExplorer = modelExplorer ?? ExpressionMetadataProvider.FromStringExpression(expression, viewContext.ViewData, _metadataProvider); + var metadata = modelExplorer.Metadata; + if (allowMultiple && metadata.IsCollectionType) + { + metadata = metadata.ElementMetadata; + } - var enumNames = modelExplorer.Metadata.EnumNamesAndValues; - var isTargetEnum = modelExplorer.Metadata.IsEnum; - var innerType = - Nullable.GetUnderlyingType(modelExplorer.Metadata.ModelType) ?? modelExplorer.Metadata.ModelType; + var enumNames = metadata.EnumNamesAndValues; + var isTargetEnum = metadata.IsEnum; + + // Logic below assumes isTargetEnum and enumNames are consistent. Confirm that expectation is met. + Debug.Assert(isTargetEnum ^ enumNames == null); + + var innerType = Nullable.GetUnderlyingType(metadata.ModelType) ?? metadata.ModelType; // Convert raw value collection to strings. var currentValues = new HashSet(StringComparer.OrdinalIgnoreCase); @@ -841,13 +849,18 @@ namespace Microsoft.AspNet.Mvc.Rendering var integerString = enumValue.ToString("d"); currentValues.Add(integerString); - // Add all simple names for this value. - var matchingNames = enumNames - .Where(kvp => string.Equals(integerString, kvp.Value, StringComparison.Ordinal)) - .Select(kvp => kvp.Key); - foreach (var name in matchingNames) + // isTargetEnum may be false when raw value has a different type than the target e.g. ViewData + // contains enum values and property has type int or string. + if (isTargetEnum) { - currentValues.Add(name); + // Add all simple names for this value. + var matchingNames = enumNames + .Where(kvp => string.Equals(integerString, kvp.Value, StringComparison.Ordinal)) + .Select(kvp => kvp.Key); + foreach (var name in matchingNames) + { + currentValues.Add(name); + } } } } diff --git a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs b/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs index 3ff8d2fe91..7e13d12f4b 100644 --- a/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs +++ b/test/Microsoft.AspNet.Mvc.Abstractions.Test/ModelBinding/ModelMetadataTest.cs @@ -269,6 +269,14 @@ namespace Microsoft.AspNet.Mvc.ModelBinding } } + public override ModelMetadata ElementMetadata + { + get + { + throw new NotImplementedException(); + } + } + public override IEnumerable> EnumDisplayNamesAndValues { get diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs index a8698440d6..0394b8ffe0 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/Metadata/DefaultModelMetadataTest.cs @@ -2,7 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; #if !DNXCORE50 using Moq; @@ -52,6 +54,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata Assert.Null(metadata.DisplayFormatString); Assert.Null(metadata.DisplayName); Assert.Null(metadata.EditFormatString); + Assert.Null(metadata.ElementMetadata); Assert.Null(metadata.EnumDisplayNamesAndValues); Assert.Null(metadata.EnumNamesAndValues); Assert.Null(metadata.NullDisplayText); @@ -106,6 +109,69 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata Assert.Equal(typeof(Exception), metadata.ContainerType); } + [Theory] + [InlineData(typeof(object))] + [InlineData(typeof(int))] + [InlineData(typeof(NonCollectionType))] + [InlineData(typeof(string))] + public void ElementMetadata_ReturnsNull_ForNonCollections(Type modelType) + { + // Arrange + var provider = new EmptyModelMetadataProvider(); + var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); + + var key = ModelMetadataIdentity.ForType(modelType); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); + + var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); + + // Act + var elementMetadata = metadata.ElementMetadata; + + // Assert + Assert.Null(elementMetadata); + } + + [Theory] + [InlineData(typeof(int[]), typeof(int))] + [InlineData(typeof(List), typeof(string))] + [InlineData(typeof(DerivedList), typeof(int))] + [InlineData(typeof(IEnumerable), typeof(object))] + [InlineData(typeof(IEnumerable), typeof(string))] + [InlineData(typeof(Collection), typeof(int))] + [InlineData(typeof(Dictionary), typeof(KeyValuePair))] + [InlineData(typeof(DerivedDictionary), typeof(KeyValuePair))] + public void ElementMetadata_ReturnsExpectedMetadata(Type modelType, Type elementType) + { + // Arrange + var provider = new EmptyModelMetadataProvider(); + var detailsProvider = new EmptyCompositeMetadataDetailsProvider(); + + var key = ModelMetadataIdentity.ForType(modelType); + var cache = new DefaultMetadataDetails(key, new ModelAttributes(new object[0])); + + var metadata = new DefaultModelMetadata(provider, detailsProvider, cache); + + // Act + var elementMetadata = metadata.ElementMetadata; + + // Assert + Assert.NotNull(elementMetadata); + Assert.Equal(elementType, elementMetadata.ModelType); + } + + private class NonCollectionType + { + } + + private class DerivedList : List + { + } + + private class DerivedDictionary : Dictionary + { + } + [Theory] [InlineData(typeof(string))] [InlineData(typeof(IDisposable))] @@ -160,7 +226,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Metadata var expectedProperties = new DefaultModelMetadata[] { new DefaultModelMetadata( - provider.Object, + provider.Object, detailsProvider, new DefaultMetadataDetails( ModelMetadataIdentity.ForProperty(typeof(int), "Prop1", typeof(string)), diff --git a/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperSelectTest.cs b/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperSelectTest.cs index 7c433349a9..3a6d223596 100644 --- a/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperSelectTest.cs +++ b/test/Microsoft.AspNet.Mvc.Extensions.Test/Rendering/HtmlHelperSelectTest.cs @@ -874,7 +874,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.Equal(expectedHtml, html.ToString()); } - [Fact(Skip = "#2664, throws ArgumentNullException")] + [Fact] public void ListBoxNotInTemplate_GetsViewDataEntry_IfModelStateEmpty() { // Arrange @@ -899,7 +899,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.Equal(expectedHtml, html.ToString()); } - [Fact(Skip = "#2664, throws ArgumentNullException")] + [Fact(Skip = "#1487, incorrectly matches Property1 entry (without prefix) in ViewData.")] public void ListBoxInTemplate_GetsViewDataEntry_IfModelStateEmpty() { // Arrange @@ -927,7 +927,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.Equal(expectedHtml, html.ToString()); } - [Fact(Skip = "#2664, throws ArgumentNullException")] + [Fact(Skip = "#1487, incorrectly matches Property1 entry (without prefix) in ViewData.")] public void ListBoxInTemplate_GetsPropertyOfViewDataEntry_IfModelStateEmptyAndNoViewDataEntryWithPrefix() { // Arrange @@ -954,7 +954,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.Equal(expectedHtml, html.ToString()); } - [Fact(Skip = "#2664, throws ArgumentNullException")] + [Fact] public void ListBoxNotInTemplate_GetsPropertyOfModel_IfModelStateAndViewDataEmpty() { // Arrange @@ -970,7 +970,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Assert.Equal(expectedHtml, html.ToString()); } - [Fact(Skip = "#2664, throws ArgumentNullException")] + [Fact] public void ListBoxInTemplate_GetsPropertyOfModel_IfModelStateAndViewDataEmpty() { // Arrange