From 948982ebff1f792ece694be1e7fcdf1d1f07023d Mon Sep 17 00:00:00 2001 From: Henk Mollema Date: Wed, 28 Jun 2017 23:23:51 +0200 Subject: [PATCH] Create custom collection for model binder providers Fixes #6161 --- .../Formatters/FormatterCollection.cs | 12 +++- .../ApplicationModelConventionCollection.cs | 57 ++++++++++++++++ .../MetadataDetailsProviderCollection.cs | 57 ++++++++++++++++ .../ModelBinderProviderCollection.cs | 57 ++++++++++++++++ .../ModelValidatorProviderCollection.cs | 57 ++++++++++++++++ .../ValueProviderFactoryCollection.cs | 57 ++++++++++++++++ .../MvcOptions.cs | 22 +++---- ...plicationModelConventionCollectionTests.cs | 66 +++++++++++++++++++ .../Formatters/FormatterCollectionTest.cs | 19 ++++++ .../MetadataDetailsProviderCollectionTests.cs | 57 ++++++++++++++++ .../ModelBinderProviderCollectionTests.cs | 65 ++++++++++++++++++ .../ModelValidatorProviderCollectionTests.cs | 65 ++++++++++++++++++ .../ValueProviderFactoryCollectionTests.cs | 66 +++++++++++++++++++ 13 files changed, 645 insertions(+), 12 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/ApplicationModelConventionCollection.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/MetadataDetailsProviderCollection.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderProviderCollection.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ModelValidatorProviderCollection.cs create mode 100644 src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ValueProviderFactoryCollection.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/ApplicationModelConventionCollectionTests.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/MetadataDetailsProviderCollectionTests.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBinderProviderCollectionTests.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Validation/ModelValidatorProviderCollectionTests.cs create mode 100644 test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ValueProviderFactoryCollectionTests.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Abstractions/Formatters/FormatterCollection.cs b/src/Microsoft.AspNetCore.Mvc.Abstractions/Formatters/FormatterCollection.cs index 7d53e0273e..401febb5cf 100644 --- a/src/Microsoft.AspNetCore.Mvc.Abstractions/Formatters/FormatterCollection.cs +++ b/src/Microsoft.AspNetCore.Mvc.Abstractions/Formatters/FormatterCollection.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. 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.Collections.ObjectModel; @@ -34,11 +35,20 @@ namespace Microsoft.AspNetCore.Mvc.Formatters /// /// The type to remove. public void RemoveType() where T : TFormatter + { + RemoveType(typeof(T)); + } + + /// + /// Removes all formatters of the specified type. + /// + /// The type to remove. + public void RemoveType(Type formatterType) { for (var i = Count - 1; i >= 0; i--) { var formatter = this[i]; - if (formatter is T) + if (formatter.GetType() == formatterType) { RemoveAt(i); } diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/ApplicationModelConventionCollection.cs b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/ApplicationModelConventionCollection.cs new file mode 100644 index 0000000000..e0ee53c2ce --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Core/ApplicationModels/ApplicationModelConventionCollection.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. 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.Collections.ObjectModel; + +namespace Microsoft.AspNetCore.Mvc.ApplicationModels +{ + /// + /// Represents a collection of application model conventions. + /// + public class ApplicationModelConventionCollection : Collection + { + /// + /// Initializes a new instance of the class that is empty. + /// + public ApplicationModelConventionCollection() + { + } + + /// + /// Initializes a new instance of the class + /// as a wrapper for the specified list. + /// + /// The list that is wrapped by the new collection. + public ApplicationModelConventionCollection(IList applicationModelConventions) + : base(applicationModelConventions) + { + } + + /// + /// Removes all application model conventions of the specified type. + /// + /// The type to remove. + public void RemoveType() where TApplicationModelConvention : IApplicationModelConvention + { + RemoveType(typeof(TApplicationModelConvention)); + } + + /// + /// Removes all application model conventions of the specified type. + /// + /// The type to remove. + public void RemoveType(Type applicationModelConventionType) + { + for (var i = Count - 1; i >= 0; i--) + { + var applicationModelConvention = this[i]; + if (applicationModelConvention.GetType() == applicationModelConventionType) + { + RemoveAt(i); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/MetadataDetailsProviderCollection.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/MetadataDetailsProviderCollection.cs new file mode 100644 index 0000000000..4eba80f496 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Metadata/MetadataDetailsProviderCollection.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. 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.Collections.ObjectModel; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata +{ + /// + /// Represents a collection of metadata details providers. + /// + public class MetadataDetailsProviderCollection : Collection + { + /// + /// Initializes a new instance of the class that is empty. + /// + public MetadataDetailsProviderCollection() + { + } + + /// + /// Initializes a new instance of the class + /// as a wrapper for the specified list. + /// + /// The list that is wrapped by the new collection. + public MetadataDetailsProviderCollection(IList metadataDetailsProviders) + : base(metadataDetailsProviders) + { + } + + /// + /// Removes all metadata details providers of the specified type. + /// + /// The type to remove. + public void RemoveType() where TMetadataDetailsProvider : IMetadataDetailsProvider + { + RemoveType(typeof(TMetadataDetailsProvider)); + } + + /// + /// Removes all metadata details providers of the specified type. + /// + /// The type to remove. + public void RemoveType(Type metadataDetailsProviderType) + { + for (var i = Count - 1; i >= 0; i--) + { + var metadataDetailsProvider = this[i]; + if (metadataDetailsProvider.GetType() == metadataDetailsProviderType) + { + RemoveAt(i); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderProviderCollection.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderProviderCollection.cs new file mode 100644 index 0000000000..0bfccb3e10 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ModelBinderProviderCollection.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. 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.Collections.ObjectModel; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding +{ + /// + /// Represents a collection of model binder providers. + /// + public class ModelBinderProviderCollection : Collection + { + /// + /// Initializes a new instance of the class that is empty. + /// + public ModelBinderProviderCollection() + { + } + + /// + /// Initializes a new instance of the class + /// as a wrapper for the specified list. + /// + /// The list that is wrapped by the new collection. + public ModelBinderProviderCollection(IList modelBinderProviders) + : base(modelBinderProviders) + { + } + + /// + /// Removes all model binder providers of the specified type. + /// + /// The type to remove. + public void RemoveType() where TModelBinderProvider : IModelBinderProvider + { + RemoveType(typeof(TModelBinderProvider)); + } + + /// + /// Removes all model binder providers of the specified type. + /// + /// The type to remove. + public void RemoveType(Type modelBinderProviderType) + { + for (var i = Count - 1; i >= 0; i--) + { + var modelBinderProvider = this[i]; + if (modelBinderProvider.GetType() == modelBinderProviderType) + { + RemoveAt(i); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ModelValidatorProviderCollection.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ModelValidatorProviderCollection.cs new file mode 100644 index 0000000000..58e9213ca2 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/Validation/ModelValidatorProviderCollection.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. 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.Collections.ObjectModel; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation +{ + /// + /// Represents a collection of model validator providers. + /// + public class ModelValidatorProviderCollection : Collection + { + /// + /// Initializes a new instance of the class that is empty. + /// + public ModelValidatorProviderCollection() + { + } + + /// + /// Initializes a new instance of the class + /// as a wrapper for the specified list. + /// + /// The list that is wrapped by the new collection. + public ModelValidatorProviderCollection(IList modelValidatorProviders) + : base(modelValidatorProviders) + { + } + + /// + /// Removes all model validator providers of the specified type. + /// + /// The type to remove. + public void RemoveType() where TModelValidatorProvider : IModelValidatorProvider + { + RemoveType(typeof(TModelValidatorProvider)); + } + + /// + /// Removes all model validator providers of the specified type. + /// + /// The type to remove. + public void RemoveType(Type modelValidatorProviderType) + { + for (var i = Count - 1; i >= 0; i--) + { + var modelValidatorProvider = this[i]; + if (modelValidatorProvider.GetType() == modelValidatorProviderType) + { + RemoveAt(i); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ValueProviderFactoryCollection.cs b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ValueProviderFactoryCollection.cs new file mode 100644 index 0000000000..e85fbd0f09 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.Core/ModelBinding/ValueProviderFactoryCollection.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. 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.Collections.ObjectModel; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding +{ + /// + /// Represents a collection of value provider factories. + /// + public class ValueProviderFactoryCollection : Collection + { + /// + /// Initializes a new instance of the class that is empty. + /// + public ValueProviderFactoryCollection() + { + } + + /// + /// Initializes a new instance of the class + /// as a wrapper for the specified list. + /// + /// The list that is wrapped by the new collection. + public ValueProviderFactoryCollection(IList valueProviderFactories) + : base(valueProviderFactories) + { + } + + /// + /// Removes all value provider factories of the specified type. + /// + /// The type to remove. + public void RemoveType() where TValueProviderFactory : IValueProviderFactory + { + RemoveType(typeof(TValueProviderFactory)); + } + + /// + /// Removes all value provider factories of the specified type. + /// + /// The type to remove. + public void RemoveType(Type valueProviderFactoryType) + { + for (var i = Count - 1; i >= 0; i--) + { + var valueProviderFactory = this[i]; + if (valueProviderFactory.GetType() == valueProviderFactoryType) + { + RemoveAt(i); + } + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Mvc.Core/MvcOptions.cs b/src/Microsoft.AspNetCore.Mvc.Core/MvcOptions.cs index d8de256a7a..24de911424 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/MvcOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/MvcOptions.cs @@ -22,16 +22,16 @@ namespace Microsoft.AspNetCore.Mvc public MvcOptions() { CacheProfiles = new Dictionary(StringComparer.OrdinalIgnoreCase); - Conventions = new List(); + Conventions = new ApplicationModelConventionCollection(); Filters = new FilterCollection(); FormatterMappings = new FormatterMappings(); InputFormatters = new FormatterCollection(); OutputFormatters = new FormatterCollection(); - ModelBinderProviders = new List(); + ModelBinderProviders = new ModelBinderProviderCollection(); ModelBindingMessageProvider = new DefaultModelBindingMessageProvider(); - ModelMetadataDetailsProviders = new List(); - ModelValidatorProviders = new List(); - ValueProviderFactories = new List(); + ModelMetadataDetailsProviders = new MetadataDetailsProviderCollection(); + ModelValidatorProviders = new ModelValidatorProviderCollection(); + ValueProviderFactories = new ValueProviderFactoryCollection(); } /// @@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Mvc /// Gets a list of instances that will be applied to /// the when discovering actions. /// - public IList Conventions { get; } + public ApplicationModelConventionCollection Conventions { get; } /// /// Gets a collection of which are used to construct filters that @@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// Gets a list of s used by this application. /// - public IList ModelBinderProviders { get; } + public ModelBinderProviderCollection ModelBinderProviders { get; } /// /// Gets the default . Changes here are copied to the @@ -122,12 +122,12 @@ namespace Microsoft.AspNetCore.Mvc ///
  • /// /// - public IList ModelMetadataDetailsProviders { get; } + public MetadataDetailsProviderCollection ModelMetadataDetailsProviders { get; } /// /// Gets a list of s used by this application. /// - public IList ModelValidatorProviders { get; } + public ModelValidatorProviderCollection ModelValidatorProviders { get; } /// /// Gets a list of s that are used by this application. @@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Mvc /// /// Gets a list of used by this application. /// - public IList ValueProviderFactories { get; } + public ValueProviderFactoryCollection ValueProviderFactories { get; } /// /// Gets or sets the SSL port that is used by this application when @@ -163,4 +163,4 @@ namespace Microsoft.AspNetCore.Mvc /// public bool RequireHttpsPermanent { get; set; } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/ApplicationModelConventionCollectionTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/ApplicationModelConventionCollectionTests.cs new file mode 100644 index 0000000000..3202e01e30 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ApplicationModel/ApplicationModelConventionCollectionTests.cs @@ -0,0 +1,66 @@ +// Copyright (c) .NET Foundation. 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.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.ApplicationModels +{ + public class ApplicationModelConventionCollectionTests + { + [Fact] + public void RemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ApplicationModelConventionCollection + { + new FooApplicationModelConvention(), + new BarApplicationModelConvention(), + new FooApplicationModelConvention() + }; + + // Act + collection.RemoveType(typeof(FooApplicationModelConvention)); + + // Assert + var convention = Assert.Single(collection); + Assert.IsType(convention); + } + + [Fact] + public void GenericRemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ApplicationModelConventionCollection + { + new FooApplicationModelConvention(), + new BarApplicationModelConvention(), + new FooApplicationModelConvention() + }; + + // Act + collection.RemoveType(); + + // Assert + var convention = Assert.Single(collection); + Assert.IsType(convention); + } + + private class FooApplicationModelConvention : IApplicationModelConvention + { + public void Apply(ApplicationModel application) + { + throw new NotImplementedException(); + } + } + + private class BarApplicationModelConvention : IApplicationModelConvention + { + public void Apply(ApplicationModel application) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatterCollectionTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatterCollectionTest.cs index 741526a8ca..79922d1d62 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatterCollectionTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Formatters/FormatterCollectionTest.cs @@ -10,6 +10,25 @@ namespace Microsoft.AspNetCore.Mvc.Formatters { public class FormatterCollectionTest { + [Fact] + public void NonGenericRemoveType_RemovesAllOfType() + { + // Arrange + var collection = new FormatterCollection + { + new TestOutputFormatter(), + new AnotherTestOutputFormatter(), + new TestOutputFormatter() + }; + + // Act + collection.RemoveType(typeof(TestOutputFormatter)); + + // Assert + var formatter = Assert.Single(collection); + Assert.IsType(typeof(AnotherTestOutputFormatter), formatter); + } + [Fact] public void RemoveType_RemovesAllOfType() { diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/MetadataDetailsProviderCollectionTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/MetadataDetailsProviderCollectionTests.cs new file mode 100644 index 0000000000..0db4306979 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Metadata/MetadataDetailsProviderCollectionTests.cs @@ -0,0 +1,57 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding.Metadata +{ + public class MetadataDetailsProviderCollectionTests + { + [Fact] + public void RemoveType_RemovesAllOfType() + { + // Arrange + var collection = new MetadataDetailsProviderCollection + { + new FooMetadataDetailsProvider(), + new BarMetadataDetailsProvider(), + new FooMetadataDetailsProvider() + }; + + // Act + collection.RemoveType(typeof(FooMetadataDetailsProvider)); + + // Assert + var provider = Assert.Single(collection); + Assert.IsType(provider); + } + + [Fact] + public void GenericRemoveType_RemovesAllOfType() + { + // Arrange + var collection = new MetadataDetailsProviderCollection + { + new FooMetadataDetailsProvider(), + new BarMetadataDetailsProvider(), + new FooMetadataDetailsProvider() + }; + + // Act + collection.RemoveType(); + + // Assert + var provider = Assert.Single(collection); + Assert.IsType(provider); + } + + private class FooMetadataDetailsProvider : IMetadataDetailsProvider + { + } + + private class BarMetadataDetailsProvider : IMetadataDetailsProvider + { + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBinderProviderCollectionTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBinderProviderCollectionTests.cs new file mode 100644 index 0000000000..4cc5b138bf --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ModelBinderProviderCollectionTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding +{ + public class ModelBinderProviderCollectionTests + { + [Fact] + public void RemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ModelBinderProviderCollection + { + new FooModelBinderProvider(), + new BarModelBinderProvider(), + new FooModelBinderProvider() + }; + + // Act + collection.RemoveType(typeof(FooModelBinderProvider)); + + // Assert + var provider = Assert.Single(collection); + Assert.IsType(provider); + } + + [Fact] + public void GenericRemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ModelBinderProviderCollection + { + new FooModelBinderProvider(), + new BarModelBinderProvider(), + new FooModelBinderProvider() + }; + + // Act + collection.RemoveType(); + + // Assert + var provider = Assert.Single(collection); + Assert.IsType(provider); + } + + private class FooModelBinderProvider : IModelBinderProvider + { + public IModelBinder GetBinder(ModelBinderProviderContext context) + { + throw new NotImplementedException(); + } + } + + private class BarModelBinderProvider : IModelBinderProvider + { + public IModelBinder GetBinder(ModelBinderProviderContext context) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Validation/ModelValidatorProviderCollectionTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Validation/ModelValidatorProviderCollectionTests.cs new file mode 100644 index 0000000000..9f4f1c1d79 --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/Validation/ModelValidatorProviderCollectionTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding.Validation +{ + public class ModelValidatorProviderCollectionTests + { + [Fact] + public void RemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ModelValidatorProviderCollection + { + new FooModelValidatorProvider(), + new BarModelValidatorProvider(), + new FooModelValidatorProvider() + }; + + // Act + collection.RemoveType(typeof(FooModelValidatorProvider)); + + // Assert + var provider = Assert.Single(collection); + Assert.IsType(provider); + } + + [Fact] + public void GenericRemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ModelValidatorProviderCollection + { + new FooModelValidatorProvider(), + new BarModelValidatorProvider(), + new FooModelValidatorProvider() + }; + + // Act + collection.RemoveType(); + + // Assert + var provider = Assert.Single(collection); + Assert.IsType(provider); + } + + private class FooModelValidatorProvider : IModelValidatorProvider + { + public void CreateValidators(ModelValidatorProviderContext context) + { + throw new NotImplementedException(); + } + } + + private class BarModelValidatorProvider : IModelValidatorProvider + { + public void CreateValidators(ModelValidatorProviderContext context) + { + throw new NotImplementedException(); + } + } + } +} diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ValueProviderFactoryCollectionTests.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ValueProviderFactoryCollectionTests.cs new file mode 100644 index 0000000000..f516d3778b --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/ModelBinding/ValueProviderFactoryCollectionTests.cs @@ -0,0 +1,66 @@ +// Copyright (c) .NET Foundation. 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.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.ModelBinding +{ + public class ValueProviderFactoryCollectionTests + { + [Fact] + public void RemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ValueProviderFactoryCollection + { + new FooValueProviderFactory(), + new BarValueProviderFactory(), + new FooValueProviderFactory() + }; + + // Act + collection.RemoveType(typeof(FooValueProviderFactory)); + + // Assert + var factory = Assert.Single(collection); + Assert.IsType(factory); + } + + [Fact] + public void GenericRemoveType_RemovesAllOfType() + { + // Arrange + var collection = new ValueProviderFactoryCollection + { + new FooValueProviderFactory(), + new BarValueProviderFactory(), + new FooValueProviderFactory() + }; + + // Act + collection.RemoveType(); + + // Assert + var factory = Assert.Single(collection); + Assert.IsType(factory); + } + + private class FooValueProviderFactory : IValueProviderFactory + { + public Task CreateValueProviderAsync(ValueProviderFactoryContext context) + { + throw new NotImplementedException(); + } + } + + private class BarValueProviderFactory : IValueProviderFactory + { + public Task CreateValueProviderAsync(ValueProviderFactoryContext context) + { + throw new NotImplementedException(); + } + } + } +}