diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/IOptionDescriptor.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/IOptionDescriptor.cs new file mode 100644 index 0000000000..1258976432 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/IOptionDescriptor.cs @@ -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 +{ + /// + /// Encapsulates information that describes a option on . + /// + /// The type of the option. + public interface IOptionDescriptor + { + /// + /// Gets the type of the described by this + /// . + /// + Type OptionType { get; } + + /// + /// Gets the instance of described by this + /// . + /// + TOption Instance { get; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/InputFormatterDescriptor.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/InputFormatterDescriptor.cs index 8786acf4a4..496b9b7691 100644 --- a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/InputFormatterDescriptor.cs +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/InputFormatterDescriptor.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.OptionDescriptors /// /// Creates a new instance of . /// - /// A type that the descriptor represents. + /// A type that the descriptor represents. /// public InputFormatterDescriptor([NotNull] Type type) : base(type) diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ModelBinderDescriptorExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ModelBinderDescriptorExtensions.cs index 5ef0d6c8ee..1e1027f85f 100644 --- a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ModelBinderDescriptorExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ModelBinderDescriptorExtensions.cs @@ -80,5 +80,23 @@ namespace Microsoft.AspNet.Mvc descriptors.Insert(index, descriptor); return descriptor; } + + /// + /// Removes instances of from a descriptor collection + /// where the type exactly matches . + /// + /// A type that implements . + /// A list of ModelBinderDescriptors. + public static void RemoveTypesOf([NotNull] this IList descriptors) + where TInstance : class, IModelBinder + { + for (int i = descriptors.Count - 1; i >= 0; i--) + { + if (descriptors[i].OptionType == typeof(TInstance)) + { + descriptors.RemoveAt(i); + } + } + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptor.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptor.cs index 4a07fc3302..e10085e7fc 100644 --- a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptor.cs +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptor.cs @@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Mvc.OptionDescriptors /// Encapsulates information that describes a option on . /// /// The type of the option. - public class OptionDescriptor + public class OptionDescriptor : IOptionDescriptor { /// /// Creates a new instance of . diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptorExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptorExtensions.cs new file mode 100644 index 0000000000..2f08788e48 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OptionDescriptorExtensions.cs @@ -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 +{ + /// + /// Extension methods for collections of option descriptors. + /// + public static class OptionDescriptorExtensions + { + /// + /// Returns the only instance of from a sequence of option descriptors. + /// + /// The type of the instance to find. + /// A sequence of . + /// The only instance of from a sequence of + /// . + /// + /// Thrown if there is not exactly one in the sequence. + public static TInstance InstanceOf( + [NotNull] this IEnumerable> descriptors) + { + var instance = descriptors + .Single(descriptor => descriptor.OptionType == typeof(TInstance) && descriptor.Instance != null) + .Instance; + return (TInstance)instance; + } + + /// + /// Returns the only instance of from a sequence of option descriptors, + /// or a default value if the sequence is empty. + /// + /// The type of the instance to find. + /// A sequence of . + /// The only instance of from a sequence of + /// , + /// or a default value if the sequence is empty. + /// + /// Thrown if there is more than one in the sequence. + public static TInstance InstanceOfOrDefault([NotNull] this + IEnumerable> 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; + } + + /// + /// Returns all the instances of from a sequence of option descriptors. + /// + /// The type of the instances to find. + /// A sequence of . + /// An IEnumerable of that contains instances from a sequence + /// of . + public static IEnumerable InstancesOf([NotNull] this + IEnumerable> descriptors) + { + var instances = descriptors + .Where(descriptor => descriptor.OptionType == typeof(TInstance) && descriptor.Instance != null) + .Select(d => (TInstance)d.Instance); + return instances; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OutputFormatterDescriptorExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OutputFormatterDescriptorExtensions.cs index 786ea292c5..8fb42bea41 100644 --- a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OutputFormatterDescriptorExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/OutputFormatterDescriptorExtensions.cs @@ -79,5 +79,23 @@ namespace Microsoft.AspNet.Mvc descriptors.Insert(index, descriptor); return descriptor; } + + /// + /// Removes instances of from a descriptor collection + /// where the type exactly matches . + /// + /// A type that implements . + /// A list of OutputFormatterDescriptors. + public static void RemoveTypesOf([NotNull] this IList descriptors) + where TInstance : class, IOutputFormatter + { + for (int i = descriptors.Count - 1; i >= 0; i--) + { + if (descriptors[i].OptionType == typeof(TInstance)) + { + descriptors.RemoveAt(i); + } + } + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ValueProviderFactoryDescriptorExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ValueProviderFactoryDescriptorExtensions.cs index d1731743d2..e30390041c 100644 --- a/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ValueProviderFactoryDescriptorExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/OptionDescriptors/ValueProviderFactoryDescriptorExtensions.cs @@ -84,5 +84,23 @@ namespace Microsoft.AspNet.Mvc descriptors.Insert(index, descriptor); return descriptor; } + + /// + /// Removes instances of from a descriptor collection + /// where the type exactly matches . + /// + /// A type that implements . + /// A list of ValueProviderFactoryDescriptors. + public static void RemoveTypesOf([NotNull] this IList descriptors) + where TInstance : class, IValueProviderFactory + { + for (int i = descriptors.Count - 1; i >= 0; i--) + { + if (descriptors[i].OptionType == typeof(TInstance)) + { + descriptors.RemoveAt(i); + } + } + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ModelBinderDescriptorExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ModelBinderDescriptorExtensionsTest.cs index c42eb1b5d7..83a13749c4 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ModelBinderDescriptorExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ModelBinderDescriptorExtensionsTest.cs @@ -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()); + modelBinders.Add(typeof(ByteArrayModelBinder)); + modelBinders.Add(Mock.Of()); + + // Act + modelBinders.RemoveTypesOf(); + + // Assert + Assert.DoesNotContain(modelBinders, descriptor => descriptor.OptionType == typeof(ByteArrayModelBinder)); + } } } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OptionDescriptorExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OptionDescriptorExtensionsTest.cs new file mode 100644 index 0000000000..07e02dfb9a --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OptionDescriptorExtensionsTest.cs @@ -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()); + formatters.Add(new JsonInputFormatter()); + + // Act & Assert + Assert.Throws(() => formatters.InstanceOf()); + } + + [Fact] + public void InputFormatters_InstanceOf_ThrowsInvalidOperationExceptionIfNoInstance() + { + // Arrange + var formatters = new MvcOptions().InputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonInputFormatter)); + + // Act & Assert + Assert.Throws(() => formatters.InstanceOf()); + } + + [Fact] + public void InputFormatters_InstanceOf_ReturnsInstanceOfIInputFormatterIfOneExists() + { + // Arrange + var formatters = new MvcOptions().InputFormatters; + formatters.Add(Mock.Of()); + var jsonFormatter = new JsonInputFormatter(); + formatters.Add(jsonFormatter); + formatters.Add(typeof(JsonInputFormatter)); + + // Act + var formatter = formatters.InstanceOf(); + + // Assert + Assert.NotNull(formatter); + Assert.IsType(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()); + formatters.Add(new JsonInputFormatter()); + + // Act & Assert + Assert.Throws(() => formatters.InstanceOfOrDefault()); + } + + [Fact] + public void InputFormatters_InstanceOfOrDefault_ReturnsNullIfNoInstance() + { + // Arrange + var formatters = new MvcOptions().InputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonInputFormatter)); + + // Act + var formatter = formatters.InstanceOfOrDefault(); + + // Assert + Assert.Null(formatter); + } + + [Fact] + public void InputFormatters_InstanceOfOrDefault_ReturnsInstanceOfIInputFormatterIfOneExists() + { + // Arrange + var formatters = new MvcOptions().InputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonInputFormatter)); + var jsonFormatter = new JsonInputFormatter(); + formatters.Add(jsonFormatter); + + // Act + var formatter = formatters.InstanceOfOrDefault(); + + // Assert + Assert.NotNull(formatter); + Assert.IsType(formatter); + Assert.Same(jsonFormatter, formatter); + } + + [Fact] + public void InputFormatters_InstancesOf_ReturnsEmptyCollectionIfNoneExist() + { + // Arrange + var formatters = new MvcOptions().InputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonInputFormatter)); + + // Act + var jsonFormatters = formatters.InstancesOf(); + + // 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(); + var formatter3 = new JsonInputFormatter(); + var formatter4 = Mock.Of(); + formatters.Add(formatter1); + formatters.Add(formatter2); + formatters.Add(formatter3); + formatters.Add(formatter4); + + var expectedFormatters = new List { formatter1, formatter3 }; + + // Act + var jsonFormatters = formatters.InstancesOf().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()); + formatters.Add(new JsonOutputFormatter()); + + // Act & Assert + Assert.Throws(() => formatters.InstanceOf()); + } + + [Fact] + public void OutputFormatters_InstanceOf_ThrowsInvalidOperationExceptionIfNoInstance() + { + // Arrange + var formatters = new MvcOptions().OutputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonOutputFormatter)); + + // Act & Assert + Assert.Throws(() => formatters.InstanceOf()); + } + + [Fact] + public void OutputFormatters_InstanceOf_ReturnsInstanceOfIInputFormatterIfOneExists() + { + // Arrange + var formatters = new MvcOptions().OutputFormatters; + formatters.Add(Mock.Of()); + var jsonFormatter = new JsonOutputFormatter(); + formatters.Add(jsonFormatter); + formatters.Add(typeof(JsonOutputFormatter)); + + // Act + var formatter = formatters.InstanceOf(); + + // Assert + Assert.NotNull(formatter); + Assert.IsType(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()); + formatters.Add(new JsonOutputFormatter()); + + // Act & Assert + Assert.Throws(() => formatters.InstanceOfOrDefault()); + } + + [Fact] + public void OutputFormatters_InstanceOfOrDefault_ReturnsNullIfNoInstance() + { + // Arrange + var formatters = new MvcOptions().OutputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonOutputFormatter)); + + // Act + var formatter = formatters.InstanceOfOrDefault(); + + // Assert + Assert.Null(formatter); + } + + [Fact] + public void OutputFormatters_InstanceOfOrDefault_ReturnsInstanceOfIOutputFormatterIfOneExists() + { + // Arrange + var formatters = new MvcOptions().OutputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonOutputFormatter)); + var jsonFormatter = new JsonOutputFormatter(); + formatters.Add(jsonFormatter); + + // Act + var formatter = formatters.InstanceOfOrDefault(); + + // Assert + Assert.NotNull(formatter); + Assert.IsType(formatter); + Assert.Same(jsonFormatter, formatter); + } + + [Fact] + public void OutputFormatters_InstancesOf_ReturnsEmptyCollectionIfNoneExist() + { + // Arrange + var formatters = new MvcOptions().OutputFormatters; + formatters.Add(Mock.Of()); + formatters.Add(typeof(JsonOutputFormatter)); + + // Act + var jsonFormatters = formatters.InstancesOf(); + + // 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(); + var formatter3 = new JsonOutputFormatter(); + var formatter4 = Mock.Of(); + formatters.Add(formatter1); + formatters.Add(formatter2); + formatters.Add(formatter3); + formatters.Add(formatter4); + + var expectedFormatters = new List { formatter1, formatter3 }; + + // Act + var jsonFormatters = formatters.InstancesOf().ToList(); + + // Assert + Assert.NotEmpty(jsonFormatters); + Assert.Equal(jsonFormatters, expectedFormatters); + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OutputFormatterDescriptorExtensionTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OutputFormatterDescriptorExtensionTest.cs index 9bf587a656..6b6bfc9320 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OutputFormatterDescriptorExtensionTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/OutputFormatterDescriptorExtensionTest.cs @@ -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()); + formatters.Add(typeof(JsonOutputFormatter)); + formatters.Add(Mock.Of()); + + // Act + formatters.RemoveTypesOf(); + + // Assert + Assert.DoesNotContain(formatters, descriptor => descriptor.OptionType == typeof(JsonOutputFormatter)); + } } -} -#endif +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ValueProviderFactoryDescriptorExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ValueProviderFactoryDescriptorExtensionsTest.cs index c555af233f..731a3b869d 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ValueProviderFactoryDescriptorExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/OptionDescriptors/ValueProviderFactoryDescriptorExtensionsTest.cs @@ -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()); + factories.Add(typeof(FormValueProviderFactory)); + factories.Add(Mock.Of()); + + // Act + factories.RemoveTypesOf(); + + // Assert + Assert.DoesNotContain(factories, descriptor => descriptor.OptionType == typeof(FormValueProviderFactory)); + } + private class TestValueProviderFactory : IValueProviderFactory { public IValueProvider GetValueProvider(ValueProviderFactoryContext context)