[Resolves Issue #1787] Added InstanceOf, InstanceOfOrDefault, InstancesOf extension methods to IEnumerable<IOptionDescriptor<object>>.

Added RemoveTypesOf extension method to OutputFormatterDescriptor, ModelBinderDescriptor, ValueProviderFactoryDescriptor.
This commit is contained in:
Anthony Sneed 2015-01-28 16:18:24 +01:00
parent 57c04835de
commit 2c21c7c9c7
11 changed files with 488 additions and 5 deletions

View File

@ -0,0 +1,26 @@
// 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;
namespace Microsoft.AspNet.Mvc.OptionDescriptors
{
/// <summary>
/// Encapsulates information that describes a <typeparamref name="TOption"/> option on <see cref="MvcOptions"/>.
/// </summary>
/// <typeparam name="TOption">The type of the option.</typeparam>
public interface IOptionDescriptor<out TOption>
{
/// <summary>
/// Gets the type of the <typeparamref name="TOption"/> described by this
/// <see cref="IOptionDescriptor{TOption}"/>.
/// </summary>
Type OptionType { get; }
/// <summary>
/// Gets the instance of <typeparamref name="TOption"/> described by this
/// <see cref="IOptionDescriptor{TOption}"/>.
/// </summary>
TOption Instance { get; }
}
}

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.OptionDescriptors
/// <summary>
/// Creates a new instance of <see cref="InputFormatterDescriptor"/>.
/// </summary>
/// <param name="type">A <see cref="IOutputFormatter"/> type that the descriptor represents.
/// <param name="type">A <see cref="IInputFormatter"/> type that the descriptor represents.
/// </param>
public InputFormatterDescriptor([NotNull] Type type)
: base(type)

View File

@ -80,5 +80,23 @@ namespace Microsoft.AspNet.Mvc
descriptors.Insert(index, descriptor);
return descriptor;
}
/// <summary>
/// Removes instances of <typeparamref name="TInstance"/> from a descriptor collection
/// where the type exactly matches <typeparamref name="TInstance"/>.
/// </summary>
/// <typeparam name="TInstance">A type that implements <see cref="IModelBinder"/>.</typeparam>
/// <param name="descriptors">A list of ModelBinderDescriptors.</param>
public static void RemoveTypesOf<TInstance>([NotNull] this IList<ModelBinderDescriptor> descriptors)
where TInstance : class, IModelBinder
{
for (int i = descriptors.Count - 1; i >= 0; i--)
{
if (descriptors[i].OptionType == typeof(TInstance))
{
descriptors.RemoveAt(i);
}
}
}
}
}

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.OptionDescriptors
/// Encapsulates information that describes a <typeparamref name="TOption"/> option on <see cref="MvcOptions"/> .
/// </summary>
/// <typeparam name="TOption">The type of the option.</typeparam>
public class OptionDescriptor<TOption>
public class OptionDescriptor<TOption> : IOptionDescriptor<TOption>
{
/// <summary>
/// Creates a new instance of <see cref="OptionDescriptor{TOption}"/>.

View File

@ -0,0 +1,74 @@
// 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.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.OptionDescriptors;
namespace Microsoft.AspNet.Mvc
{
/// <summary>
/// Extension methods for collections of option descriptors.
/// </summary>
public static class OptionDescriptorExtensions
{
/// <summary>
/// Returns the only instance of <typeparamref name="TInstance"/> from a sequence of option descriptors.
/// </summary>
/// <typeparam name="TInstance">The type of the instance to find.</typeparam>
/// <param name="descriptors">A sequence of <see cref="IOptionDescriptor{object}"/>.</param>
/// <returns>The only instance of <typeparamref name="TInstance"/> from a sequence of
/// <see cref="IOptionDescriptor{object}"/>.</returns>
/// <exception cref="InvalidOperationException">
/// Thrown if there is not exactly one <typeparamref name="TInstance"/> in the sequence.</exception>
public static TInstance InstanceOf<TInstance>(
[NotNull] this IEnumerable<IOptionDescriptor<object>> descriptors)
{
var instance = descriptors
.Single(descriptor => descriptor.OptionType == typeof(TInstance) && descriptor.Instance != null)
.Instance;
return (TInstance)instance;
}
/// <summary>
/// Returns the only instance of <typeparamref name="TInstance"/> from a sequence of option descriptors,
/// or a default value if the sequence is empty.
/// </summary>
/// <typeparam name="TInstance">The type of the instance to find.</typeparam>
/// <param name="descriptors">A sequence of <see cref="IOptionDescriptor{object}"/>.</param>
/// <returns>The only instance of <typeparamref name="TInstance"/> from a sequence of
/// <see cref="IOptionDescriptor{object}"/>,
/// or a default value if the sequence is empty.</returns>
/// <exception cref="InvalidOperationException">
/// Thrown if there is more than one <typeparamref name="TInstance"/> in the sequence.</exception>
public static TInstance InstanceOfOrDefault<TInstance>([NotNull] this
IEnumerable<IOptionDescriptor<object>> descriptors)
{
var item = descriptors
.SingleOrDefault(
descriptor => descriptor.OptionType == typeof(TInstance) && descriptor.Instance != null);
var instance = default(TInstance);
if (item != null)
{
instance = (TInstance)item.Instance;
}
return instance;
}
/// <summary>
/// Returns all the instances of <typeparamref name="TInstance"/> from a sequence of option descriptors.
/// </summary>
/// <typeparam name="TInstance">The type of the instances to find.</typeparam>
/// <param name="descriptors">A sequence of <see cref="IOptionDescriptor{object}"/>.</param>
/// <returns>An IEnumerable of <typeparamref name="TInstance"/> that contains instances from a sequence
/// of <see cref="IOptionDescriptor{object}"/>.</returns>
public static IEnumerable<TInstance> InstancesOf<TInstance>([NotNull] this
IEnumerable<IOptionDescriptor<object>> descriptors)
{
var instances = descriptors
.Where(descriptor => descriptor.OptionType == typeof(TInstance) && descriptor.Instance != null)
.Select(d => (TInstance)d.Instance);
return instances;
}
}
}

View File

@ -79,5 +79,23 @@ namespace Microsoft.AspNet.Mvc
descriptors.Insert(index, descriptor);
return descriptor;
}
/// <summary>
/// Removes instances of <typeparamref name="TInstance"/> from a descriptor collection
/// where the type exactly matches <typeparamref name="TInstance"/>.
/// </summary>
/// <typeparam name="TInstance">A type that implements <see cref="IOutputFormatter"/>.</typeparam>
/// <param name="descriptors">A list of OutputFormatterDescriptors.</param>
public static void RemoveTypesOf<TInstance>([NotNull] this IList<OutputFormatterDescriptor> descriptors)
where TInstance : class, IOutputFormatter
{
for (int i = descriptors.Count - 1; i >= 0; i--)
{
if (descriptors[i].OptionType == typeof(TInstance))
{
descriptors.RemoveAt(i);
}
}
}
}
}

View File

@ -84,5 +84,23 @@ namespace Microsoft.AspNet.Mvc
descriptors.Insert(index, descriptor);
return descriptor;
}
/// <summary>
/// Removes instances of <typeparamref name="TInstance"/> from a descriptor collection
/// where the type exactly matches <typeparamref name="TInstance"/>.
/// </summary>
/// <typeparam name="TInstance">A type that implements <see cref="IValueProviderFactory"/>.</typeparam>
/// <param name="descriptors">A list of ValueProviderFactoryDescriptors.</param>
public static void RemoveTypesOf<TInstance>([NotNull] this IList<ValueProviderFactoryDescriptor> descriptors)
where TInstance : class, IValueProviderFactory
{
for (int i = descriptors.Count - 1; i >= 0; i--)
{
if (descriptors[i].OptionType == typeof(TInstance))
{
descriptors.RemoveAt(i);
}
}
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.OptionDescriptors;
using Moq;
@ -68,5 +69,22 @@ namespace Microsoft.AspNet.Mvc
Assert.Equal(type2, collection[2].OptionType);
Assert.Equal(type1, collection[3].OptionType);
}
[Fact]
public void ModelBinders_RemoveTypesOf_RemovesDescriptorsOfIModelBinder()
{
// Arrange
var modelBinders = new MvcOptions().ModelBinders;
modelBinders.Add(new ByteArrayModelBinder());
modelBinders.Add(Mock.Of<IModelBinder>());
modelBinders.Add(typeof(ByteArrayModelBinder));
modelBinders.Add(Mock.Of<IModelBinder>());
// Act
modelBinders.RemoveTypesOf<ByteArrayModelBinder>();
// Assert
Assert.DoesNotContain(modelBinders, descriptor => descriptor.OptionType == typeof(ByteArrayModelBinder));
}
}
}

View File

@ -0,0 +1,276 @@
// 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.Linq;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.OptionDescriptors
{
public class OptionDescriptorExtensionsTest
{
[Fact]
public void InputFormatters_InstanceOf_ThrowsInvalidOperationExceptionIfMoreThanOnceInstance()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(new JsonInputFormatter());
formatters.Add(Mock.Of<IInputFormatter>());
formatters.Add(new JsonInputFormatter());
// Act & Assert
Assert.Throws<InvalidOperationException>(() => formatters.InstanceOf<JsonInputFormatter>());
}
[Fact]
public void InputFormatters_InstanceOf_ThrowsInvalidOperationExceptionIfNoInstance()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(Mock.Of<IInputFormatter>());
formatters.Add(typeof(JsonInputFormatter));
// Act & Assert
Assert.Throws<InvalidOperationException>(() => formatters.InstanceOf<JsonInputFormatter>());
}
[Fact]
public void InputFormatters_InstanceOf_ReturnsInstanceOfIInputFormatterIfOneExists()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(Mock.Of<IInputFormatter>());
var jsonFormatter = new JsonInputFormatter();
formatters.Add(jsonFormatter);
formatters.Add(typeof(JsonInputFormatter));
// Act
var formatter = formatters.InstanceOf<JsonInputFormatter>();
// Assert
Assert.NotNull(formatter);
Assert.IsType<JsonInputFormatter>(formatter);
Assert.Same(jsonFormatter, formatter);
}
[Fact]
public void InputFormatters_InstanceOfOrDefault_ThrowsInvalidOperationExceptionIfMoreThanOnceInstance()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(new JsonInputFormatter());
formatters.Add(Mock.Of<IInputFormatter>());
formatters.Add(new JsonInputFormatter());
// Act & Assert
Assert.Throws<InvalidOperationException>(() => formatters.InstanceOfOrDefault<JsonInputFormatter>());
}
[Fact]
public void InputFormatters_InstanceOfOrDefault_ReturnsNullIfNoInstance()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(Mock.Of<IInputFormatter>());
formatters.Add(typeof(JsonInputFormatter));
// Act
var formatter = formatters.InstanceOfOrDefault<JsonInputFormatter>();
// Assert
Assert.Null(formatter);
}
[Fact]
public void InputFormatters_InstanceOfOrDefault_ReturnsInstanceOfIInputFormatterIfOneExists()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(Mock.Of<IInputFormatter>());
formatters.Add(typeof(JsonInputFormatter));
var jsonFormatter = new JsonInputFormatter();
formatters.Add(jsonFormatter);
// Act
var formatter = formatters.InstanceOfOrDefault<JsonInputFormatter>();
// Assert
Assert.NotNull(formatter);
Assert.IsType<JsonInputFormatter>(formatter);
Assert.Same(jsonFormatter, formatter);
}
[Fact]
public void InputFormatters_InstancesOf_ReturnsEmptyCollectionIfNoneExist()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(Mock.Of<IInputFormatter>());
formatters.Add(typeof(JsonInputFormatter));
// Act
var jsonFormatters = formatters.InstancesOf<JsonInputFormatter>();
// Assert
Assert.Empty(jsonFormatters);
}
[Fact]
public void InputFormatters_InstancesOf_ReturnsNonEmptyCollectionIfSomeExist()
{
// Arrange
var formatters = new MvcOptions().InputFormatters;
formatters.Add(typeof(JsonInputFormatter));
var formatter1 = new JsonInputFormatter();
var formatter2 = Mock.Of<IInputFormatter>();
var formatter3 = new JsonInputFormatter();
var formatter4 = Mock.Of<IInputFormatter>();
formatters.Add(formatter1);
formatters.Add(formatter2);
formatters.Add(formatter3);
formatters.Add(formatter4);
var expectedFormatters = new List<JsonInputFormatter> { formatter1, formatter3 };
// Act
var jsonFormatters = formatters.InstancesOf<JsonInputFormatter>().ToList();
// Assert
Assert.NotEmpty(jsonFormatters);
Assert.Equal(jsonFormatters, expectedFormatters);
}
[Fact]
public void OutputFormatters_InstanceOf_ThrowsInvalidOperationExceptionIfMoreThanOnceInstance()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(new JsonOutputFormatter());
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(new JsonOutputFormatter());
// Act & Assert
Assert.Throws<InvalidOperationException>(() => formatters.InstanceOf<JsonOutputFormatter>());
}
[Fact]
public void OutputFormatters_InstanceOf_ThrowsInvalidOperationExceptionIfNoInstance()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(typeof(JsonOutputFormatter));
// Act & Assert
Assert.Throws<InvalidOperationException>(() => formatters.InstanceOf<JsonOutputFormatter>());
}
[Fact]
public void OutputFormatters_InstanceOf_ReturnsInstanceOfIInputFormatterIfOneExists()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(Mock.Of<IOutputFormatter>());
var jsonFormatter = new JsonOutputFormatter();
formatters.Add(jsonFormatter);
formatters.Add(typeof(JsonOutputFormatter));
// Act
var formatter = formatters.InstanceOf<JsonOutputFormatter>();
// Assert
Assert.NotNull(formatter);
Assert.IsType<JsonOutputFormatter>(formatter);
Assert.Same(jsonFormatter, formatter);
}
[Fact]
public void OutputFormatters_InstanceOfOrDefault_ThrowsInvalidOperationExceptionIfMoreThanOnceInstance()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(new JsonOutputFormatter());
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(new JsonOutputFormatter());
// Act & Assert
Assert.Throws<InvalidOperationException>(() => formatters.InstanceOfOrDefault<JsonOutputFormatter>());
}
[Fact]
public void OutputFormatters_InstanceOfOrDefault_ReturnsNullIfNoInstance()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(typeof(JsonOutputFormatter));
// Act
var formatter = formatters.InstanceOfOrDefault<JsonOutputFormatter>();
// Assert
Assert.Null(formatter);
}
[Fact]
public void OutputFormatters_InstanceOfOrDefault_ReturnsInstanceOfIOutputFormatterIfOneExists()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(typeof(JsonOutputFormatter));
var jsonFormatter = new JsonOutputFormatter();
formatters.Add(jsonFormatter);
// Act
var formatter = formatters.InstanceOfOrDefault<JsonOutputFormatter>();
// Assert
Assert.NotNull(formatter);
Assert.IsType<JsonOutputFormatter>(formatter);
Assert.Same(jsonFormatter, formatter);
}
[Fact]
public void OutputFormatters_InstancesOf_ReturnsEmptyCollectionIfNoneExist()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(typeof(JsonOutputFormatter));
// Act
var jsonFormatters = formatters.InstancesOf<JsonOutputFormatter>();
// Assert
Assert.Empty(jsonFormatters);
}
[Fact]
public void OutputFormatters_InstancesOf_ReturnsNonEmptyCollectionIfSomeExist()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(typeof(JsonOutputFormatter));
var formatter1 = new JsonOutputFormatter();
var formatter2 = Mock.Of<IOutputFormatter>();
var formatter3 = new JsonOutputFormatter();
var formatter4 = Mock.Of<IOutputFormatter>();
formatters.Add(formatter1);
formatters.Add(formatter2);
formatters.Add(formatter3);
formatters.Add(formatter4);
var expectedFormatters = new List<JsonOutputFormatter> { formatter1, formatter3 };
// Act
var jsonFormatters = formatters.InstancesOf<JsonOutputFormatter>().ToList();
// Assert
Assert.NotEmpty(jsonFormatters);
Assert.Equal(jsonFormatters, expectedFormatters);
}
}
}

View File

@ -1,9 +1,10 @@
// 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.
#if ASPNET50
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.OptionDescriptors;
using Moq;
using Xunit;
@ -69,6 +70,22 @@ namespace Microsoft.AspNet.Mvc.Core.Test
Assert.Equal(type2, collection[2].OptionType);
Assert.Equal(type1, collection[3].OptionType);
}
[Fact]
public void OutputFormatters_RemoveTypesOf_RemovesDescriptorsOfIOutputFormatter()
{
// Arrange
var formatters = new MvcOptions().OutputFormatters;
formatters.Add(new JsonOutputFormatter());
formatters.Add(Mock.Of<IOutputFormatter>());
formatters.Add(typeof(JsonOutputFormatter));
formatters.Add(Mock.Of<IOutputFormatter>());
// Act
formatters.RemoveTypesOf<JsonOutputFormatter>();
// Assert
Assert.DoesNotContain(formatters, descriptor => descriptor.OptionType == typeof(JsonOutputFormatter));
}
}
}
#endif
}

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.OptionDescriptors;
using Moq;
@ -64,6 +65,23 @@ namespace Microsoft.AspNet.Mvc
Assert.Same(valueProviderFactory, collection[0].Instance);
}
[Fact]
public void ValueProviderFactories_RemoveTypesOf_RemovesDescriptorsOfIValueProviderFactory()
{
// Arrange
var factories = new MvcOptions().ValueProviderFactories;
factories.Add(new FormValueProviderFactory());
factories.Add(Mock.Of<IValueProviderFactory>());
factories.Add(typeof(FormValueProviderFactory));
factories.Add(Mock.Of<IValueProviderFactory>());
// Act
factories.RemoveTypesOf<FormValueProviderFactory>();
// Assert
Assert.DoesNotContain(factories, descriptor => descriptor.OptionType == typeof(FormValueProviderFactory));
}
private class TestValueProviderFactory : IValueProviderFactory
{
public IValueProvider GetValueProvider(ValueProviderFactoryContext context)