Create custom collection for model binder providers

Fixes #6161
This commit is contained in:
Henk Mollema 2017-06-28 23:23:51 +02:00 committed by Pranav K
parent 873a2fe17f
commit 948982ebff
13 changed files with 645 additions and 12 deletions

View File

@ -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
/// </summary>
/// <typeparam name="T">The type to remove.</typeparam>
public void RemoveType<T>() where T : TFormatter
{
RemoveType(typeof(T));
}
/// <summary>
/// Removes all formatters of the specified type.
/// </summary>
/// <param name="formatterType">The type to remove.</param>
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);
}

View File

@ -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
{
/// <summary>
/// Represents a collection of application model conventions.
/// </summary>
public class ApplicationModelConventionCollection : Collection<IApplicationModelConvention>
{
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationModelConventionCollection"/> class that is empty.
/// </summary>
public ApplicationModelConventionCollection()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationModelConventionCollection"/> class
/// as a wrapper for the specified list.
/// </summary>
/// <param name="applicationModelConventions">The list that is wrapped by the new collection.</param>
public ApplicationModelConventionCollection(IList<IApplicationModelConvention> applicationModelConventions)
: base(applicationModelConventions)
{
}
/// <summary>
/// Removes all application model conventions of the specified type.
/// </summary>
/// <typeparam name="TApplicationModelConvention">The type to remove.</typeparam>
public void RemoveType<TApplicationModelConvention>() where TApplicationModelConvention : IApplicationModelConvention
{
RemoveType(typeof(TApplicationModelConvention));
}
/// <summary>
/// Removes all application model conventions of the specified type.
/// </summary>
/// <param name="applicationModelConventionType">The type to remove.</param>
public void RemoveType(Type applicationModelConventionType)
{
for (var i = Count - 1; i >= 0; i--)
{
var applicationModelConvention = this[i];
if (applicationModelConvention.GetType() == applicationModelConventionType)
{
RemoveAt(i);
}
}
}
}
}

View File

@ -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
{
/// <summary>
/// Represents a collection of metadata details providers.
/// </summary>
public class MetadataDetailsProviderCollection : Collection<IMetadataDetailsProvider>
{
/// <summary>
/// Initializes a new instance of the <see cref="MetadataDetailsProviderCollection"/> class that is empty.
/// </summary>
public MetadataDetailsProviderCollection()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MetadataDetailsProviderCollection"/> class
/// as a wrapper for the specified list.
/// </summary>
/// <param name="metadataDetailsProviders">The list that is wrapped by the new collection.</param>
public MetadataDetailsProviderCollection(IList<IMetadataDetailsProvider> metadataDetailsProviders)
: base(metadataDetailsProviders)
{
}
/// <summary>
/// Removes all metadata details providers of the specified type.
/// </summary>
/// <typeparam name="TMetadataDetailsProvider">The type to remove.</typeparam>
public void RemoveType<TMetadataDetailsProvider>() where TMetadataDetailsProvider : IMetadataDetailsProvider
{
RemoveType(typeof(TMetadataDetailsProvider));
}
/// <summary>
/// Removes all metadata details providers of the specified type.
/// </summary>
/// <param name="metadataDetailsProviderType">The type to remove.</param>
public void RemoveType(Type metadataDetailsProviderType)
{
for (var i = Count - 1; i >= 0; i--)
{
var metadataDetailsProvider = this[i];
if (metadataDetailsProvider.GetType() == metadataDetailsProviderType)
{
RemoveAt(i);
}
}
}
}
}

View File

@ -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
{
/// <summary>
/// Represents a collection of model binder providers.
/// </summary>
public class ModelBinderProviderCollection : Collection<IModelBinderProvider>
{
/// <summary>
/// Initializes a new instance of the <see cref="ModelBinderProviderCollection"/> class that is empty.
/// </summary>
public ModelBinderProviderCollection()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ModelBinderProviderCollection"/> class
/// as a wrapper for the specified list.
/// </summary>
/// <param name="modelBinderProviders">The list that is wrapped by the new collection.</param>
public ModelBinderProviderCollection(IList<IModelBinderProvider> modelBinderProviders)
: base(modelBinderProviders)
{
}
/// <summary>
/// Removes all model binder providers of the specified type.
/// </summary>
/// <typeparam name="TModelBinderProvider">The type to remove.</typeparam>
public void RemoveType<TModelBinderProvider>() where TModelBinderProvider : IModelBinderProvider
{
RemoveType(typeof(TModelBinderProvider));
}
/// <summary>
/// Removes all model binder providers of the specified type.
/// </summary>
/// <param name="modelBinderProviderType">The type to remove.</param>
public void RemoveType(Type modelBinderProviderType)
{
for (var i = Count - 1; i >= 0; i--)
{
var modelBinderProvider = this[i];
if (modelBinderProvider.GetType() == modelBinderProviderType)
{
RemoveAt(i);
}
}
}
}
}

View File

@ -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
{
/// <summary>
/// Represents a collection of model validator providers.
/// </summary>
public class ModelValidatorProviderCollection : Collection<IModelValidatorProvider>
{
/// <summary>
/// Initializes a new instance of the <see cref="ModelValidatorProviderCollection"/> class that is empty.
/// </summary>
public ModelValidatorProviderCollection()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ModelValidatorProviderCollection"/> class
/// as a wrapper for the specified list.
/// </summary>
/// <param name="modelValidatorProviders">The list that is wrapped by the new collection.</param>
public ModelValidatorProviderCollection(IList<IModelValidatorProvider> modelValidatorProviders)
: base(modelValidatorProviders)
{
}
/// <summary>
/// Removes all model validator providers of the specified type.
/// </summary>
/// <typeparam name="TModelValidatorProvider">The type to remove.</typeparam>
public void RemoveType<TModelValidatorProvider>() where TModelValidatorProvider : IModelValidatorProvider
{
RemoveType(typeof(TModelValidatorProvider));
}
/// <summary>
/// Removes all model validator providers of the specified type.
/// </summary>
/// <param name="modelValidatorProviderType">The type to remove.</param>
public void RemoveType(Type modelValidatorProviderType)
{
for (var i = Count - 1; i >= 0; i--)
{
var modelValidatorProvider = this[i];
if (modelValidatorProvider.GetType() == modelValidatorProviderType)
{
RemoveAt(i);
}
}
}
}
}

View File

@ -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
{
/// <summary>
/// Represents a collection of value provider factories.
/// </summary>
public class ValueProviderFactoryCollection : Collection<IValueProviderFactory>
{
/// <summary>
/// Initializes a new instance of the <see cref="ValueProviderFactoryCollection"/> class that is empty.
/// </summary>
public ValueProviderFactoryCollection()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ValueProviderFactoryCollection"/> class
/// as a wrapper for the specified list.
/// </summary>
/// <param name="valueProviderFactories">The list that is wrapped by the new collection.</param>
public ValueProviderFactoryCollection(IList<IValueProviderFactory> valueProviderFactories)
: base(valueProviderFactories)
{
}
/// <summary>
/// Removes all value provider factories of the specified type.
/// </summary>
/// <typeparam name="TValueProviderFactory">The type to remove.</typeparam>
public void RemoveType<TValueProviderFactory>() where TValueProviderFactory : IValueProviderFactory
{
RemoveType(typeof(TValueProviderFactory));
}
/// <summary>
/// Removes all value provider factories of the specified type.
/// </summary>
/// <param name="valueProviderFactoryType">The type to remove.</param>
public void RemoveType(Type valueProviderFactoryType)
{
for (var i = Count - 1; i >= 0; i--)
{
var valueProviderFactory = this[i];
if (valueProviderFactory.GetType() == valueProviderFactoryType)
{
RemoveAt(i);
}
}
}
}
}

View File

@ -22,16 +22,16 @@ namespace Microsoft.AspNetCore.Mvc
public MvcOptions()
{
CacheProfiles = new Dictionary<string, CacheProfile>(StringComparer.OrdinalIgnoreCase);
Conventions = new List<IApplicationModelConvention>();
Conventions = new ApplicationModelConventionCollection();
Filters = new FilterCollection();
FormatterMappings = new FormatterMappings();
InputFormatters = new FormatterCollection<IInputFormatter>();
OutputFormatters = new FormatterCollection<IOutputFormatter>();
ModelBinderProviders = new List<IModelBinderProvider>();
ModelBinderProviders = new ModelBinderProviderCollection();
ModelBindingMessageProvider = new DefaultModelBindingMessageProvider();
ModelMetadataDetailsProviders = new List<IMetadataDetailsProvider>();
ModelValidatorProviders = new List<IModelValidatorProvider>();
ValueProviderFactories = new List<IValueProviderFactory>();
ModelMetadataDetailsProviders = new MetadataDetailsProviderCollection();
ModelValidatorProviders = new ModelValidatorProviderCollection();
ValueProviderFactories = new ValueProviderFactoryCollection();
}
/// <summary>
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Mvc
/// Gets a list of <see cref="IApplicationModelConvention"/> instances that will be applied to
/// the <see cref="ApplicationModel"/> when discovering actions.
/// </summary>
public IList<IApplicationModelConvention> Conventions { get; }
public ApplicationModelConventionCollection Conventions { get; }
/// <summary>
/// Gets a collection of <see cref="IFilterMetadata"/> which are used to construct filters that
@ -100,7 +100,7 @@ namespace Microsoft.AspNetCore.Mvc
/// <summary>
/// Gets a list of <see cref="IModelBinderProvider"/>s used by this application.
/// </summary>
public IList<IModelBinderProvider> ModelBinderProviders { get; }
public ModelBinderProviderCollection ModelBinderProviders { get; }
/// <summary>
/// Gets the default <see cref="ModelBinding.Metadata.ModelBindingMessageProvider"/>. Changes here are copied to the
@ -122,12 +122,12 @@ namespace Microsoft.AspNetCore.Mvc
/// <li><see cref="IValidationMetadataProvider"/></li>
/// </ul>
/// </remarks>
public IList<IMetadataDetailsProvider> ModelMetadataDetailsProviders { get; }
public MetadataDetailsProviderCollection ModelMetadataDetailsProviders { get; }
/// <summary>
/// Gets a list of <see cref="IModelValidatorProvider"/>s used by this application.
/// </summary>
public IList<IModelValidatorProvider> ModelValidatorProviders { get; }
public ModelValidatorProviderCollection ModelValidatorProviders { get; }
/// <summary>
/// Gets a list of <see cref="IOutputFormatter"/>s that are used by this application.
@ -150,7 +150,7 @@ namespace Microsoft.AspNetCore.Mvc
/// <summary>
/// Gets a list of <see cref="IValueProviderFactory"/> used by this application.
/// </summary>
public IList<IValueProviderFactory> ValueProviderFactories { get; }
public ValueProviderFactoryCollection ValueProviderFactories { get; }
/// <summary>
/// Gets or sets the SSL port that is used by this application when <see cref="RequireHttpsAttribute"/>
@ -163,4 +163,4 @@ namespace Microsoft.AspNetCore.Mvc
/// </summary>
public bool RequireHttpsPermanent { get; set; }
}
}
}

View File

@ -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<BarApplicationModelConvention>(convention);
}
[Fact]
public void GenericRemoveType_RemovesAllOfType()
{
// Arrange
var collection = new ApplicationModelConventionCollection
{
new FooApplicationModelConvention(),
new BarApplicationModelConvention(),
new FooApplicationModelConvention()
};
// Act
collection.RemoveType<FooApplicationModelConvention>();
// Assert
var convention = Assert.Single(collection);
Assert.IsType<BarApplicationModelConvention>(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();
}
}
}
}

View File

@ -10,6 +10,25 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
{
public class FormatterCollectionTest
{
[Fact]
public void NonGenericRemoveType_RemovesAllOfType()
{
// Arrange
var collection = new FormatterCollection<IOutputFormatter>
{
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()
{

View File

@ -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<BarMetadataDetailsProvider>(provider);
}
[Fact]
public void GenericRemoveType_RemovesAllOfType()
{
// Arrange
var collection = new MetadataDetailsProviderCollection
{
new FooMetadataDetailsProvider(),
new BarMetadataDetailsProvider(),
new FooMetadataDetailsProvider()
};
// Act
collection.RemoveType<FooMetadataDetailsProvider>();
// Assert
var provider = Assert.Single(collection);
Assert.IsType<BarMetadataDetailsProvider>(provider);
}
private class FooMetadataDetailsProvider : IMetadataDetailsProvider
{
}
private class BarMetadataDetailsProvider : IMetadataDetailsProvider
{
}
}
}

View File

@ -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<BarModelBinderProvider>(provider);
}
[Fact]
public void GenericRemoveType_RemovesAllOfType()
{
// Arrange
var collection = new ModelBinderProviderCollection
{
new FooModelBinderProvider(),
new BarModelBinderProvider(),
new FooModelBinderProvider()
};
// Act
collection.RemoveType<FooModelBinderProvider>();
// Assert
var provider = Assert.Single(collection);
Assert.IsType<BarModelBinderProvider>(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();
}
}
}
}

View File

@ -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<BarModelValidatorProvider>(provider);
}
[Fact]
public void GenericRemoveType_RemovesAllOfType()
{
// Arrange
var collection = new ModelValidatorProviderCollection
{
new FooModelValidatorProvider(),
new BarModelValidatorProvider(),
new FooModelValidatorProvider()
};
// Act
collection.RemoveType<FooModelValidatorProvider>();
// Assert
var provider = Assert.Single(collection);
Assert.IsType<BarModelValidatorProvider>(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();
}
}
}
}

View File

@ -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<BarValueProviderFactory>(factory);
}
[Fact]
public void GenericRemoveType_RemovesAllOfType()
{
// Arrange
var collection = new ValueProviderFactoryCollection
{
new FooValueProviderFactory(),
new BarValueProviderFactory(),
new FooValueProviderFactory()
};
// Act
collection.RemoveType<FooValueProviderFactory>();
// Assert
var factory = Assert.Single(collection);
Assert.IsType<BarValueProviderFactory>(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();
}
}
}
}