diff --git a/samples/MvcMinimalSample.Web/Startup.cs b/samples/MvcMinimalSample.Web/Startup.cs index bd4908a517..bad3621bed 100644 --- a/samples/MvcMinimalSample.Web/Startup.cs +++ b/samples/MvcMinimalSample.Web/Startup.cs @@ -3,6 +3,8 @@ using Microsoft.AspNet.Builder; using Microsoft.Framework.DependencyInjection; +using Microsoft.Net.Http.Headers; +using Newtonsoft.Json; namespace MvcMinimalSample.Web { @@ -10,7 +12,12 @@ namespace MvcMinimalSample.Web { public void ConfigureServices(IServiceCollection services) { - services.AddMinimalMvc(); + // Example 1 + services + .AddMvcCore() + .AddAuthorization() + .AddFormatterMappings(m => m.SetMediaTypeMappingForFormat("js", new MediaTypeHeaderValue("application/json"))) + .AddJsonFormatters(j => j.Formatting = Formatting.Indented); } public void Configure(IApplicationBuilder app) diff --git a/samples/MvcMinimalSample.Web/project.json b/samples/MvcMinimalSample.Web/project.json index 2c2be227ac..547e48632d 100644 --- a/samples/MvcMinimalSample.Web/project.json +++ b/samples/MvcMinimalSample.Web/project.json @@ -4,6 +4,8 @@ "dependencies": { "Microsoft.AspNet.Mvc.Core": "6.0.0-*", + "Microsoft.AspNet.Mvc.DataAnnotations": "6.0.0-*", + "Microsoft.AspNet.Mvc.Formatters.Json": "6.0.0-*", "Microsoft.AspNet.Hosting": "1.0.0-*", "Microsoft.AspNet.Server.WebListener": "1.0.0-*" }, diff --git a/src/Microsoft.AspNet.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcBuilderExtensions.cs new file mode 100644 index 0000000000..689fb094b1 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ApiExplorer/DependencyInjection/MvcApiExplorerMvcBuilderExtensions.cs @@ -0,0 +1,25 @@ +// 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 Microsoft.AspNet.Mvc.ApiExplorer; +using Microsoft.Framework.Internal; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcApiExplorerMvcBuilderExtensions + { + public static IMvcBuilder AddApiExplorer([NotNull] this IMvcBuilder builder) + { + AddApiExplorerServices(builder.Services); + return builder; + } + + // Internal for testing. + internal static void AddApiExplorerServices(IServiceCollection services) + { + services.TryAddSingleton(); + services.TryAddEnumerable( + ServiceDescriptor.Transient()); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcApplicationBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/Builder/MvcApplicationBuilderExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.Mvc.Core/MvcApplicationBuilderExtensions.cs rename to src/Microsoft.AspNet.Mvc.Core/Builder/MvcApplicationBuilderExtensions.cs diff --git a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/IMvcBuilder.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/IMvcBuilder.cs new file mode 100644 index 0000000000..2bde1db657 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/IMvcBuilder.cs @@ -0,0 +1,10 @@ +// 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. + +namespace Microsoft.Framework.DependencyInjection +{ + public interface IMvcBuilder + { + IServiceCollection Services { get; } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreMvcBuilderExtensions.cs new file mode 100644 index 0000000000..ca5783c5b0 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreMvcBuilderExtensions.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 Microsoft.AspNet.Authorization; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.ApplicationModels; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcCoreMvcBuilderExtensions + { + public static IMvcBuilder AddFormatterMappings(this IMvcBuilder builder) + { + AddFormatterMappingsServices(builder.Services); + return builder; + } + + public static IMvcBuilder AddFormatterMappings( + this IMvcBuilder builder, + Action setupAction) + { + AddFormatterMappingsServices(builder.Services); + + if (setupAction != null) + { + builder.Services.Configure((options) => setupAction(options.FormatterMappings)); + } + + return builder; + } + + // Internal for testing. + internal static void AddFormatterMappingsServices(IServiceCollection services) + { + services.TryAddTransient(); + } + + public static IMvcBuilder AddAuthorization(this IMvcBuilder builder) + { + AddAuthorizationServices(builder.Services); + return builder; + } + + public static IMvcBuilder AddAuthorization(this IMvcBuilder builder, Action setupAction) + { + AddAuthorizationServices(builder.Services); + + if (setupAction != null) + { + builder.Services.Configure(setupAction); + } + + return builder; + } + + // Internal for testing. + internal static void AddAuthorizationServices(IServiceCollection services) + { + services.AddAuthorization(); + + services.TryAddEnumerable( + ServiceDescriptor.Transient()); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs similarity index 89% rename from src/Microsoft.AspNet.Mvc.Core/MvcCoreServiceCollectionExtensions.cs rename to src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs index 2db49214df..9999394bb6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/MvcCoreServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs @@ -20,13 +20,26 @@ namespace Microsoft.Framework.DependencyInjection { public static class MvcCoreServiceCollectionExtensions { - public static IServiceCollection AddMinimalMvc([NotNull] this IServiceCollection services) + public static IMvcBuilder AddMvcCore([NotNull] this IServiceCollection services) { ConfigureDefaultServices(services); AddMvcCoreServices(services); - return services; + return new MvcBuilder() { Services = services, }; + } + + public static IMvcBuilder AddMvcCore( + [NotNull] this IServiceCollection services, + [NotNull] Action setupAction) + { + ConfigureDefaultServices(services); + + AddMvcCoreServices(services); + + services.Configure(setupAction); + + return new MvcBuilder() { Services = services, }; } /// @@ -48,7 +61,9 @@ namespace Microsoft.Framework.DependencyInjection // Options // services.TryAddEnumerable( - ServiceDescriptor.Transient, CoreMvcOptionsSetup>()); + ServiceDescriptor.Transient, MvcCoreMvcOptionsSetup>()); + services.TryAddEnumerable( + ServiceDescriptor.Transient, MvcCoreRouteOptionsSetup>()); // // Action Discovery @@ -138,9 +153,11 @@ namespace Microsoft.Framework.DependencyInjection services.AddOptions(); services.AddRouting(); services.AddNotifier(); + } - services.TryAddEnumerable( - ServiceDescriptor.Transient, MvcRouteOptionsSetup>()); + private class MvcBuilder : IMvcBuilder + { + public IServiceCollection Services { get; set; } } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs b/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs index 3f4992cfc5..e519f4bb11 100644 --- a/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc /// /// The /// The - public FormatFilter(IOptions options, IScopedInstance actionContext) + public FormatFilter(IOptions options, IScopedInstance actionContext) { IsActive = true; Format = GetFormat(actionContext.Value); diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcCacheOptions.cs b/src/Microsoft.AspNet.Mvc.Core/MvcCacheOptions.cs deleted file mode 100644 index 508ef98288..0000000000 --- a/src/Microsoft.AspNet.Mvc.Core/MvcCacheOptions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// 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; - -namespace Microsoft.AspNet.Mvc -{ - /// - /// Provides programmatic configuration for caching in the MVC framework. - /// - public class MvcCacheOptions - { - /// - /// Gets a Dictionary of CacheProfile Names, which are pre-defined settings for - /// . - /// - public IDictionary CacheProfiles { get; } = - new Dictionary(StringComparer.OrdinalIgnoreCase); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/CoreMvcOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.Core/MvcCoreMvcOptionsSetup.cs similarity index 91% rename from src/Microsoft.AspNet.Mvc.Core/CoreMvcOptionsSetup.cs rename to src/Microsoft.AspNet.Mvc.Core/MvcCoreMvcOptionsSetup.cs index b4bf49631f..ae68ccf14c 100644 --- a/src/Microsoft.AspNet.Mvc.Core/CoreMvcOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.Core/MvcCoreMvcOptionsSetup.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Metadata; using Microsoft.AspNet.Mvc.ModelBinding.Validation; @@ -12,9 +13,9 @@ namespace Microsoft.AspNet.Mvc /// /// Sets up default options for . /// - public class CoreMvcOptionsSetup : ConfigureOptions + public class MvcCoreMvcOptionsSetup : ConfigureOptions { - public CoreMvcOptionsSetup() + public MvcCoreMvcOptionsSetup() : base(ConfigureMvc) { Order = DefaultOrder.DefaultFrameworkSortOrder; @@ -60,8 +61,8 @@ namespace Microsoft.AspNet.Mvc // Any 'known' types that we bind should be marked as excluded from validation. options.ValidationExcludeFilters.Add(typeof(System.Threading.CancellationToken)); - options.ValidationExcludeFilters.Add(typeof(Http.IFormFile)); - options.ValidationExcludeFilters.Add(typeof(Http.IFormCollection)); + options.ValidationExcludeFilters.Add(typeof(IFormFile)); + options.ValidationExcludeFilters.Add(typeof(IFormCollection)); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcRouteOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.Core/MvcCoreRouteOptionsSetup.cs similarity index 88% rename from src/Microsoft.AspNet.Mvc.Core/MvcRouteOptionsSetup.cs rename to src/Microsoft.AspNet.Mvc.Core/MvcCoreRouteOptionsSetup.cs index 1ae7647a28..99b077ba6d 100644 --- a/src/Microsoft.AspNet.Mvc.Core/MvcRouteOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.Core/MvcCoreRouteOptionsSetup.cs @@ -9,9 +9,9 @@ namespace Microsoft.AspNet.Mvc /// /// Sets up MVC default options for . /// - public class MvcRouteOptionsSetup : ConfigureOptions + public class MvcCoreRouteOptionsSetup : ConfigureOptions { - public MvcRouteOptionsSetup() + public MvcCoreRouteOptionsSetup() : base(ConfigureRouting) { Order = DefaultOrder.DefaultFrameworkSortOrder; diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcFormatterMappingOptions.cs b/src/Microsoft.AspNet.Mvc.Core/MvcFormatterMappingOptions.cs deleted file mode 100644 index fe3c7bf121..0000000000 --- a/src/Microsoft.AspNet.Mvc.Core/MvcFormatterMappingOptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -namespace Microsoft.AspNet.Mvc -{ - /// - /// Provides programmatic configuration for formatter mappings in the MVC framework. - /// - public class MvcFormatterMappingOptions - { - /// - /// Used to specify mapping between the URL Format and corresponding - /// . - /// - public FormatterMappings FormatterMappings { get; } = new FormatterMappings(); - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcOptions.cs b/src/Microsoft.AspNet.Mvc.Core/MvcOptions.cs index 161c868178..290c64c1b2 100644 --- a/src/Microsoft.AspNet.Mvc.Core/MvcOptions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/MvcOptions.cs @@ -19,8 +19,10 @@ namespace Microsoft.AspNet.Mvc public MvcOptions() { + CacheProfiles = new Dictionary(StringComparer.OrdinalIgnoreCase); Conventions = new List(); Filters = new List(); + FormatterMappings = new FormatterMappings(); InputFormatters = new List(); OutputFormatters = new List(); ModelBinders = new List(); @@ -30,6 +32,18 @@ namespace Microsoft.AspNet.Mvc ValueProviderFactories = new List(); } + /// + /// Gets a Dictionary of CacheProfile Names, which are pre-defined settings for + /// . + /// + public IDictionary CacheProfiles { get; } + + /// + /// Gets a list of instances that will be applied to + /// the when discovering actions. + /// + public IList Conventions { get; } + /// /// Gets a list of which are used to construct filters that /// apply to all actions. @@ -37,20 +51,16 @@ namespace Microsoft.AspNet.Mvc public ICollection Filters { get; } /// - /// Gets a list of s that are used by this application. + /// Used to specify mapping between the URL Format and corresponding + /// . /// - public IList OutputFormatters { get; } + public FormatterMappings FormatterMappings { get; } /// /// Gets a list of s that are used by this application. /// public IList InputFormatters { get; } - /// - /// Gets a list of s used by this application. - /// - public IList ModelBinders { get; } - /// /// Gets or sets the maximum number of validation errors that are allowed by this application before further /// errors are ignored. @@ -70,26 +80,9 @@ namespace Microsoft.AspNet.Mvc } /// - /// Gets a list of s used by this application. + /// Gets a list of s used by this application. /// - public IList ModelValidatorProviders { get; } - - /// - /// Gets a list of used by this application. - /// - public IList ValueProviderFactories { get; } - - /// - /// Gets a list of instances that will be applied to - /// the when discovering actions. - /// - public IList Conventions { get; } - - /// - /// Gets or sets the flag which causes content negotiation to ignore Accept header - /// when it contains the media type */*. by default. - /// - public bool RespectBrowserAcceptHeader { get; set; } + public IList ModelBinders { get; } /// /// Gets a list of instances that will be used to @@ -106,9 +99,30 @@ namespace Microsoft.AspNet.Mvc /// public IList ModelMetadataDetailsProviders { get; } + /// + /// Gets a list of s used by this application. + /// + public IList ModelValidatorProviders { get; } + + /// + /// Gets a list of s that are used by this application. + /// + public IList OutputFormatters { get; } + + /// + /// Gets or sets the flag which causes content negotiation to ignore Accept header + /// when it contains the media type */*. by default. + /// + public bool RespectBrowserAcceptHeader { get; set; } + /// /// Gets a list of s that are used by this application. /// public IList ValidationExcludeFilters { get; } + + /// + /// Gets a list of used by this application. + /// + public IList ValueProviderFactories { get; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/ResponseCacheAttribute.cs b/src/Microsoft.AspNet.Mvc.Core/ResponseCacheAttribute.cs index 633bef7a13..5fc1ddd2c1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ResponseCacheAttribute.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ResponseCacheAttribute.cs @@ -88,7 +88,7 @@ namespace Microsoft.AspNet.Mvc public IFilterMetadata CreateInstance([NotNull] IServiceProvider serviceProvider) { - var optionsAccessor = serviceProvider.GetRequiredService>(); + var optionsAccessor = serviceProvider.GetRequiredService>(); CacheProfile selectedProfile = null; if (CacheProfileName != null) diff --git a/src/Microsoft.AspNet.Mvc.Cors/DependencyInjection/MvcCorsMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Cors/DependencyInjection/MvcCorsMvcBuilderExtensions.cs new file mode 100644 index 0000000000..38d5a1e292 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Cors/DependencyInjection/MvcCorsMvcBuilderExtensions.cs @@ -0,0 +1,52 @@ +// 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 Microsoft.AspNet.Cors.Core; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.ApplicationModels; +using Microsoft.Framework.Internal; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcJsonMvcBuilderExtensions + { + public static IMvcBuilder AddCors([NotNull] this IMvcBuilder builder) + { + AddCorsServices(builder.Services); + return builder; + } + + public static IMvcBuilder AddCors( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + AddCorsServices(builder.Services); + + if (setupAction != null) + { + builder.Services.Configure(setupAction); + } + + return builder; + } + + public static IMvcBuilder ConfigureCors( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + builder.Services.Configure(setupAction); + return builder; + } + + // Internal for testing. + internal static void AddCorsServices(IServiceCollection services) + { + services.AddCors(); + + services.TryAddEnumerable( + ServiceDescriptor.Transient()); + services.TryAddTransient(); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.DataAnnotations/DependencyInjection/MvcDataAnnotationsMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.DataAnnotations/DependencyInjection/MvcDataAnnotationsMvcBuilderExtensions.cs new file mode 100644 index 0000000000..94d9cd87bd --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.DataAnnotations/DependencyInjection/MvcDataAnnotationsMvcBuilderExtensions.cs @@ -0,0 +1,25 @@ +// 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 Microsoft.AspNet.Mvc; +using Microsoft.Framework.Internal; +using Microsoft.Framework.OptionsModel; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcDataAnnotationsMvcBuilderExtensions + { + public static IMvcBuilder AddDataAnnotations([NotNull] this IMvcBuilder builder) + { + AddDataAnnotationsServices(builder.Services); + return builder; + } + + // Internal for testing. + internal static void AddDataAnnotationsServices(IServiceCollection services) + { + services.TryAddEnumerable( + ServiceDescriptor.Transient, MvcDataAnnotationsMvcOptionsSetup>()); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.DataAnnotations/MvcDataAnnotationsMvcOptionsSetup.cs similarity index 78% rename from src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs rename to src/Microsoft.AspNet.Mvc.DataAnnotations/MvcDataAnnotationsMvcOptionsSetup.cs index 8730f2af33..3f4188dc1a 100644 --- a/src/Microsoft.AspNet.Mvc/MvcOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.DataAnnotations/MvcDataAnnotationsMvcOptionsSetup.cs @@ -1,20 +1,18 @@ // 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.Xml.Linq; using Microsoft.AspNet.Mvc.ModelBinding.Metadata; using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.Framework.OptionsModel; -using Newtonsoft.Json.Linq; namespace Microsoft.AspNet.Mvc { /// /// Sets up default options for . /// - public class MvcOptionsSetup : ConfigureOptions + public class MvcDataAnnotationsMvcOptionsSetup : ConfigureOptions { - public MvcOptionsSetup() + public MvcDataAnnotationsMvcOptionsSetup() : base(ConfigureMvc) { Order = DefaultOrder.DefaultFrameworkSortOrder + 1; @@ -24,9 +22,6 @@ namespace Microsoft.AspNet.Mvc { options.ModelMetadataDetailsProviders.Add(new DataAnnotationsMetadataProvider()); options.ModelValidatorProviders.Add(new DataAnnotationsModelValidatorProvider()); - - options.ValidationExcludeFilters.Add(typeof(JToken)); - } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Formatters.Json/DependencyInjection/MvcJsonMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Formatters.Json/DependencyInjection/MvcJsonMvcBuilderExtensions.cs new file mode 100644 index 0000000000..d25d3e50a5 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Formatters.Json/DependencyInjection/MvcJsonMvcBuilderExtensions.cs @@ -0,0 +1,49 @@ +// 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 Microsoft.AspNet.Mvc; +using Microsoft.Framework.Internal; +using Microsoft.Framework.OptionsModel; +using Newtonsoft.Json; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcJsonMvcBuilderExtensions + { + public static IMvcBuilder AddJsonFormatters([NotNull] this IMvcBuilder builder) + { + AddJsonFormatterServices(builder.Services); + return builder; + } + + public static IMvcBuilder AddJsonFormatters( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + AddJsonFormatterServices(builder.Services); + + if (setupAction != null) + { + builder.Services.Configure((options) => setupAction(options.SerializerSettings)); + } + + return builder; + } + + public static IMvcBuilder ConfigureJson( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + builder.Services.Configure(setupAction); + return builder; + } + + // Internal for testing. + internal static void AddJsonFormatterServices(IServiceCollection services) + { + services.TryAddEnumerable( + ServiceDescriptor.Transient, MvcJsonMvcOptionsSetup>()); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc/JsonPatchExtensions.cs b/src/Microsoft.AspNet.Mvc.Formatters.Json/JsonPatchExtensions.cs similarity index 100% rename from src/Microsoft.AspNet.Mvc/JsonPatchExtensions.cs rename to src/Microsoft.AspNet.Mvc.Formatters.Json/JsonPatchExtensions.cs diff --git a/src/Microsoft.AspNet.Mvc/JsonMvcOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.Formatters.Json/MvcJsonMvcOptionsSetup.cs similarity index 67% rename from src/Microsoft.AspNet.Mvc/JsonMvcOptionsSetup.cs rename to src/Microsoft.AspNet.Mvc.Formatters.Json/MvcJsonMvcOptionsSetup.cs index f186ac9aba..be527a5899 100644 --- a/src/Microsoft.AspNet.Mvc/JsonMvcOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.Formatters.Json/MvcJsonMvcOptionsSetup.cs @@ -2,13 +2,15 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Framework.OptionsModel; +using Microsoft.Net.Http.Headers; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Microsoft.AspNet.Mvc { - public class JsonMvcOptionsSetup : ConfigureOptions + public class MvcJsonMvcOptionsSetup : ConfigureOptions { - public JsonMvcOptionsSetup(IOptions jsonOptions) + public MvcJsonMvcOptionsSetup(IOptions jsonOptions) : base((_) => ConfigureMvc(_, jsonOptions.Options.SerializerSettings)) { Order = DefaultOrder.DefaultFrameworkSortOrder + 10; @@ -20,6 +22,10 @@ namespace Microsoft.AspNet.Mvc options.InputFormatters.Add(new JsonInputFormatter(serializerSettings)); options.InputFormatters.Add(new JsonPatchInputFormatter(serializerSettings)); + + options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json")); + + options.ValidationExcludeFilters.Add(typeof(JToken)); } } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs new file mode 100644 index 0000000000..1cbcfb4da6 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs @@ -0,0 +1,93 @@ +// 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 Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.Razor; +using Microsoft.AspNet.Mvc.Razor.Compilation; +using Microsoft.AspNet.Mvc.Razor.Directives; +using Microsoft.Framework.Caching.Memory; +using Microsoft.Framework.Internal; +using Microsoft.Framework.OptionsModel; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcRazorMvcBuilderExtensions + { + public static IMvcBuilder AddRazorViewEngine([NotNull] this IMvcBuilder builder) + { + builder.AddViews(); + AddRazorViewEngineServices(builder.Services); + return builder; + } + + public static IMvcBuilder AddRazorViewEngine( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + builder.AddViews(); + AddRazorViewEngineServices(builder.Services); + + if (setupAction != null) + { + builder.Services.Configure(setupAction); + } + + return builder; + } + + public static IMvcBuilder ConfigureRazorViewEngine( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + builder.Services.Configure(setupAction); + return builder; + } + + // Internal for testing. + internal static void AddRazorViewEngineServices(IServiceCollection services) + { + services.TryAddEnumerable( + ServiceDescriptor.Transient, MvcRazorMvcViewOptionsSetup>()); + services.TryAddEnumerable( + ServiceDescriptor.Transient, RazorViewEngineOptionsSetup>()); + + // Caches view locations that are valid for the lifetime of the application. + services.TryAddSingleton(); + services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => + { + var cachedFileProvider = serviceProvider.GetRequiredService>(); + return new DefaultChunkTreeCache(cachedFileProvider.Options.FileProvider); + })); + + // The host is designed to be discarded after consumption and is very inexpensive to initialize. + services.TryAddTransient(); + + // Caches compilation artifacts across the lifetime of the application. + services.TryAddSingleton(); + + // This caches compilation related details that are valid across the lifetime of the application + // and is required to be a singleton. + services.TryAddSingleton(); + + // Both the compiler cache and roslyn compilation service hold on the compilation related + // caches. RazorCompilation service is just an adapter service, and it is transient to ensure + // the IMvcRazorHost dependency does not maintain state. + services.TryAddTransient(); + + // The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory + services.TryAddScoped(); + services.TryAddTransient(); + services.TryAddSingleton(); + + // Virtual path view factory needs to stay scoped so views can get get scoped services. + services.TryAddScoped(); + + // Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict. + services.TryAddSingleton(); + + // Consumed by the Cache tag helper to cache results across the lifetime of the application. + services.TryAddSingleton(); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Razor/MvcRazorMvcViewOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.Razor/MvcRazorMvcViewOptionsSetup.cs new file mode 100644 index 0000000000..5e9cf99e52 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/MvcRazorMvcViewOptionsSetup.cs @@ -0,0 +1,21 @@ +// 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 Microsoft.Framework.OptionsModel; + +namespace Microsoft.AspNet.Mvc.Razor +{ + public class MvcRazorMvcViewOptionsSetup : ConfigureOptions + { + public MvcRazorMvcViewOptionsSetup() + : base(ConfigureMvc) + { + Order = DefaultOrder.DefaultFrameworkSortOrder; + } + + public static void ConfigureMvc(MvcViewOptions options) + { + options.ViewEngines.Add(typeof(RazorViewEngine)); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc/RazorViewEngineOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptionsSetup.cs similarity index 100% rename from src/Microsoft.AspNet.Mvc/RazorViewEngineOptionsSetup.cs rename to src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptionsSetup.cs diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs new file mode 100644 index 0000000000..5e500da126 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/DependencyInjection/MvcViewFeaturesMvcBuilderExtensions.cs @@ -0,0 +1,102 @@ +// 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 Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.ViewComponents; +using Microsoft.Framework.Internal; +using Microsoft.Framework.OptionsModel; + +namespace Microsoft.Framework.DependencyInjection +{ + public static class MvcViewFeaturesMvcBuilderExtensions + { + public static IMvcBuilder AddViews([NotNull] this IMvcBuilder builder) + { + builder.AddDataAnnotations(); + AddViewServices(builder.Services); + return builder; + } + + public static IMvcBuilder AddViews( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + builder.AddDataAnnotations(); + AddViewServices(builder.Services); + + if (setupAction != null) + { + builder.Services.Configure(setupAction); + } + + return builder; + } + + public static IMvcBuilder ConfigureViews( + [NotNull] this IMvcBuilder builder, + [NotNull] Action setupAction) + { + builder.Services.Configure(setupAction); + return builder; + } + + // Internal for testing. + internal static void AddViewServices(IServiceCollection services) + { + services.AddDataProtection(); + services.AddAntiforgery(); + services.AddWebEncoders(); + + services.TryAddEnumerable( + ServiceDescriptor.Transient, MvcViewOptionsSetup>()); + + // + // View Engine and related infrastructure + // + // The provider is inexpensive to initialize and provides ViewEngines that may require request + // specific services. + services.TryAddScoped(); + + // Support for activating ViewDataDictionary + services.TryAddEnumerable( + ServiceDescriptor + .Transient()); + + // + // HTML Helper + // + services.TryAddTransient(); + services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)); + + // DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped. + // Therefore it too is scoped. + services.TryAddScoped(); + + // + // JSON Helper + // + services.TryAddSingleton(); + services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => + { + var options = serviceProvider.GetRequiredService>().Options; + return new JsonOutputFormatter(options.SerializerSettings); + })); + + // + // View Components + // + // These do caching so they should stay singleton + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton< + IViewComponentDescriptorCollectionProvider, + DefaultViewComponentDescriptorCollectionProvider>(); + + services.TryAddTransient(); + services.TryAddSingleton(); + services.TryAddTransient(); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc/MvcViewOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/MvcViewOptionsSetup.cs similarity index 88% rename from src/Microsoft.AspNet.Mvc/MvcViewOptionsSetup.cs rename to src/Microsoft.AspNet.Mvc.ViewFeatures/MvcViewOptionsSetup.cs index 13367ff16d..b5c5110213 100644 --- a/src/Microsoft.AspNet.Mvc/MvcViewOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/MvcViewOptionsSetup.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Mvc.ModelBinding.Validation; -using Microsoft.AspNet.Mvc.Razor; using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Mvc @@ -20,9 +19,6 @@ namespace Microsoft.AspNet.Mvc public static void ConfigureMvc(MvcViewOptions options) { - // Set up ViewEngines - options.ViewEngines.Add(typeof(RazorViewEngine)); - // Set up client validators options.ClientModelValidatorProviders.Add(new DefaultClientModelValidatorProvider()); options.ClientModelValidatorProviders.Add(new DataAnnotationsClientModelValidatorProvider()); diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/project.json b/src/Microsoft.AspNet.Mvc.ViewFeatures/project.json index 8e65e238c7..e5d2ec41f5 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/project.json +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/project.json @@ -12,6 +12,7 @@ "Microsoft.AspNet.Antiforgery": "1.0.0-*", "Microsoft.AspNet.Diagnostics.Abstractions": "1.0.0-*", "Microsoft.AspNet.Mvc.Core": "6.0.0-*", + "Microsoft.AspNet.Mvc.DataAnnotations": "6.0.0-*", "Microsoft.AspNet.Mvc.Formatters.Json": "6.0.0-*", "Microsoft.Framework.BufferEntryCollection.Sources": { "version": "1.0.0-*", "type": "build" }, "Microsoft.Framework.ClosedGenericMatcher.Sources": { "version": "1.0.0-*", "type": "build" }, diff --git a/src/Microsoft.AspNet.Mvc/JsonMvcFormatterMappingOptionsSetup.cs b/src/Microsoft.AspNet.Mvc/JsonMvcFormatterMappingOptionsSetup.cs deleted file mode 100644 index 1679640f0b..0000000000 --- a/src/Microsoft.AspNet.Mvc/JsonMvcFormatterMappingOptionsSetup.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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 Microsoft.Framework.OptionsModel; -using Microsoft.Net.Http.Headers; - -namespace Microsoft.AspNet.Mvc -{ - public class JsonMvcFormatterMappingOptionsSetup : ConfigureOptions - { - public JsonMvcFormatterMappingOptionsSetup() - : base(ConfigureMvc) - { - Order = DefaultOrder.DefaultFrameworkSortOrder + 10; - } - - public static void ConfigureMvc(MvcFormatterMappingOptions options) - { - options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json")); - } - } -} diff --git a/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs index 96c45cac3e..206478cc81 100644 --- a/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc/MvcServiceCollectionExtensions.cs @@ -3,20 +3,11 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Reflection; using Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Mvc.ApiExplorer; -using Microsoft.AspNet.Mvc.ApplicationModels; using Microsoft.AspNet.Mvc.Razor; -using Microsoft.AspNet.Mvc.Razor.Compilation; -using Microsoft.AspNet.Mvc.Razor.Directives; -using Microsoft.AspNet.Mvc.Rendering; -using Microsoft.AspNet.Mvc.ViewComponents; -using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.Internal; -using Microsoft.Framework.OptionsModel; namespace Microsoft.Framework.DependencyInjection { @@ -24,35 +15,28 @@ namespace Microsoft.Framework.DependencyInjection { public static IServiceCollection AddMvc([NotNull] this IServiceCollection services) { - services.AddMinimalMvc(); + var builder = services.AddMvcCore(); - ConfigureDefaultServices(services); - - AddMvcServices(services); + builder.AddApiExplorer(); + builder.AddAuthorization(); + builder.AddCors(); + builder.AddDataAnnotations(); + builder.AddFormatterMappings(); + builder.AddJsonFormatters(); + builder.AddViews(); + builder.AddRazorViewEngine(); return services; } /// - /// Configures a set of for the application. + /// Configures a set of for the application. /// /// The services available in the application. - /// The which need to be configured. - public static void ConfigureMvcCaching( + /// The which need to be configured. + public static void ConfigureMvcViews( [NotNull] this IServiceCollection services, - [NotNull] Action setupAction) - { - services.Configure(setupAction); - } - - /// - /// Configures a set of for the application. - /// - /// The services available in the application. - /// The which need to be configured. - public static void ConfigureMvcFormatterMappings( - [NotNull] this IServiceCollection services, - [NotNull] Action setupAction) + [NotNull] Action setupAction) { services.Configure(setupAction); } @@ -69,18 +53,6 @@ namespace Microsoft.Framework.DependencyInjection services.Configure(setupAction); } - /// - /// Configures a set of for the application. - /// - /// The services available in the application. - /// The which need to be configured. - public static void ConfigureMvcViews( - [NotNull] this IServiceCollection services, - [NotNull] Action setupAction) - { - services.Configure(setupAction); - } - /// /// Register the specified as services and as a source for controller /// discovery. @@ -129,116 +101,6 @@ namespace Microsoft.Framework.DependencyInjection return WithControllersAsServices(services, controllerTypes.Select(type => type.AsType())); } - // To enable unit testing - internal static void AddMvcServices(IServiceCollection services) - { - // Options - all of these are multi-registration - services.TryAddEnumerable( - ServiceDescriptor.Transient, MvcOptionsSetup>()); - services.TryAddEnumerable( - ServiceDescriptor.Transient, JsonMvcOptionsSetup>()); - services.TryAddEnumerable( - ServiceDescriptor - .Transient, JsonMvcFormatterMappingOptionsSetup>()); - services.TryAddEnumerable( - ServiceDescriptor.Transient, MvcViewOptionsSetup>()); - services.TryAddEnumerable( - ServiceDescriptor - .Transient, RazorViewEngineOptionsSetup>()); - - // Cors - services.TryAddEnumerable( - ServiceDescriptor.Transient()); - services.TryAddTransient(); - - // Auth - services.TryAddEnumerable( - ServiceDescriptor.Transient()); - - // Support for activating ViewDataDictionary - services.TryAddEnumerable( - ServiceDescriptor - .Transient()); - - // Formatter Mappings - services.TryAddTransient(); - - // JsonOutputFormatter should use the SerializerSettings on MvcOptions - services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => - { - var options = serviceProvider.GetRequiredService>().Options; - return new JsonOutputFormatter(options.SerializerSettings); - })); - - // Razor, Views and runtime compilation - - // The provider is inexpensive to initialize and provides ViewEngines that may require request - // specific services. - services.TryAddScoped(); - - // Caches view locations that are valid for the lifetime of the application. - services.TryAddSingleton(); - services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => - { - var cachedFileProvider = serviceProvider.GetRequiredService>(); - return new DefaultChunkTreeCache(cachedFileProvider.Options.FileProvider); - })); - - // The host is designed to be discarded after consumption and is very inexpensive to initialize. - services.TryAddTransient(); - - // Caches compilation artifacts across the lifetime of the application. - services.TryAddSingleton(); - - // This caches compilation related details that are valid across the lifetime of the application - // and is required to be a singleton. - services.TryAddSingleton(); - - // Both the compiler cache and roslyn compilation service hold on the compilation related - // caches. RazorCompilation service is just an adapter service, and it is transient to ensure - // the IMvcRazorHost dependency does not maintain state. - services.TryAddTransient(); - - // The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory - services.TryAddScoped(); - services.TryAddTransient(); - services.TryAddSingleton(); - - // Virtual path view factory needs to stay scoped so views can get get scoped services. - services.TryAddScoped(); - - // View and rendering helpers - services.TryAddTransient(); - services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)); - services.TryAddSingleton(); - - // Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict. - services.TryAddSingleton(); - - // Consumed by the Cache tag helper to cache results across the lifetime of the application. - services.TryAddSingleton(); - - // DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped. - // Therefore it too is scoped. - services.TryAddScoped(); - - // These do caching so they should stay singleton - services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton< - IViewComponentDescriptorCollectionProvider, - DefaultViewComponentDescriptorCollectionProvider>(); - - services.TryAddTransient(); - services.TryAddSingleton(); - services.TryAddTransient(); - - // Api Description - services.TryAddSingleton(); - services.TryAddEnumerable( - ServiceDescriptor.Transient()); - } - /// /// Adds Mvc localization to the application. /// @@ -266,14 +128,5 @@ namespace Microsoft.Framework.DependencyInjection return services; } - - private static void ConfigureDefaultServices(IServiceCollection services) - { - services.AddDataProtection(); - services.AddAntiforgery(); - services.AddCors(); - services.AddAuthorization(); - services.AddWebEncoders(); - } } } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs index cc674064a1..ccf368e8be 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs @@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc var resultExecutingContext = mockObjects.CreateResultExecutingContext(); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Mvc ac, new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -118,11 +118,11 @@ namespace Microsoft.AspNet.Mvc var resultExecutingContext = mockObjects.CreateResultExecutingContext(); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - mockObjects.MockFormatterMappingOptions.FormatterMappings.SetMediaTypeMappingForFormat( + mockObjects.Options.FormatterMappings.SetMediaTypeMappingForFormat( format, MediaTypeHeaderValue.Parse(contentType)); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -162,7 +162,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -184,7 +184,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { produces }); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -201,11 +201,11 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects("xml", FormatSource.RouteData); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { produces }); - mockObjects.MockFormatterMappingOptions.FormatterMappings.SetMediaTypeMappingForFormat( + mockObjects.Options.FormatterMappings.SetMediaTypeMappingForFormat( "xml", MediaTypeHeaderValue.Parse("application/xml")); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -222,11 +222,11 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects("xml", FormatSource.RouteData); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { produces }); - mockObjects.MockFormatterMappingOptions.FormatterMappings.SetMediaTypeMappingForFormat( + mockObjects.Options.FormatterMappings.SetMediaTypeMappingForFormat( "xml", MediaTypeHeaderValue.Parse("application/xml;version=1")); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -248,11 +248,11 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { produces }); - mockObjects.MockFormatterMappingOptions.FormatterMappings.SetMediaTypeMappingForFormat( + mockObjects.Options.FormatterMappings.SetMediaTypeMappingForFormat( "xml", MediaTypeHeaderValue.Parse("application/xml")); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -271,7 +271,7 @@ namespace Microsoft.AspNet.Mvc // Arrange var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -294,7 +294,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resultExecutingContext = mockObjects.CreateResultExecutingContext(); var filterAttribute = new FormatFilterAttribute(); - var filter = new FormatFilter(mockObjects.IOptions, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); // Act and Assert Assert.Equal(expected, filter.IsActive); @@ -318,13 +318,12 @@ namespace Microsoft.AspNet.Mvc private class MockObjects { - public MvcOptions MockOptions { get; private set; } - public MvcFormatterMappingOptions MockFormatterMappingOptions { get; private set; } + public MvcOptions Options { get; private set; } public HttpContext MockHttpContext { get; private set; } public ActionContext MockActionContext { get; private set; } public IScopedInstance ScopedInstance { get; private set; } - public IOptions IOptions { get; private set; } + public IOptions OptionsManager { get; private set; } public MockObjects(string format = null, FormatSource? place = null) { @@ -383,24 +382,21 @@ namespace Microsoft.AspNet.Mvc string format = null, FormatSource? place = null) { + OptionsManager = new TestOptionsManager(); + // Setup options on mock service provider - MockOptions = new MvcOptions(); - MockFormatterMappingOptions = new MvcFormatterMappingOptions(); + Options = OptionsManager.Options; // Set up default output formatters. - MockOptions.OutputFormatters.Add(new HttpNoContentOutputFormatter()); - MockOptions.OutputFormatters.Add(new StringOutputFormatter()); - MockOptions.OutputFormatters.Add(new JsonOutputFormatter()); + Options.OutputFormatters.Add(new HttpNoContentOutputFormatter()); + Options.OutputFormatters.Add(new StringOutputFormatter()); + Options.OutputFormatters.Add(new JsonOutputFormatter()); // Set up default mapping for json extensions to content type - MockFormatterMappingOptions.FormatterMappings.SetMediaTypeMappingForFormat( + Options.FormatterMappings.SetMediaTypeMappingForFormat( "json", MediaTypeHeaderValue.Parse("application/json")); - var mvcOptions = new Mock>(); - mvcOptions.Setup(o => o.Options).Returns(MockFormatterMappingOptions); - IOptions = mvcOptions.Object; - // Setup MVC services on mock service provider MockActionContext = CreateMockActionContext(httpContext, format, place); var scopedInstance = new Mock>(); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs index 8e71ed6c41..8f6c7f15a4 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs @@ -111,9 +111,7 @@ namespace Microsoft.AspNet.Mvc private static IServiceProvider GetServiceProvider() { - var optionsSetup = new MvcOptionsSetup(); var options = new MvcOptions(); - optionsSetup.Configure(options); var optionsAccessor = new Mock>(); optionsAccessor.SetupGet(o => o.Options).Returns(options); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/MvcCoreServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/MvcCoreServiceCollectionExtensionsTest.cs index 1d698e4de4..d9960b797c 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/MvcCoreServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/MvcCoreServiceCollectionExtensionsTest.cs @@ -8,6 +8,7 @@ using Microsoft.AspNet.Mvc.ActionConstraints; using Microsoft.AspNet.Mvc.ApplicationModels; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Filters; +using Microsoft.AspNet.Routing; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.OptionsModel; using Moq; @@ -125,7 +126,14 @@ namespace Microsoft.AspNet.Mvc typeof(IConfigureOptions), new Type[] { - typeof(CoreMvcOptionsSetup), + typeof(MvcCoreMvcOptionsSetup), + } + }, + { + typeof(IConfigureOptions), + new Type[] + { + typeof(MvcCoreRouteOptionsSetup), } }, { diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/MvcCacheOptionsTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/MvcOptionsTest.cs similarity index 62% rename from test/Microsoft.AspNet.Mvc.Core.Test/MvcCacheOptionsTest.cs rename to test/Microsoft.AspNet.Mvc.Core.Test/MvcOptionsTest.cs index ef95a7d237..6bb3ec0010 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/MvcCacheOptionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/MvcOptionsTest.cs @@ -6,13 +6,24 @@ using Xunit; namespace Microsoft.AspNet.Mvc { - public class MvcCacheOptionsTest + public class MvcOptionsTest { + [Fact] + public void MaxValidationError_ThrowsIfValueIsOutOfRange() + { + // Arrange + var options = new MvcOptions(); + + // Act & Assert + var ex = Assert.Throws(() => options.MaxModelValidationErrors = -1); + Assert.Equal("value", ex.ParamName); + } + [Fact] public void ThrowsWhenMultipleCacheProfilesWithSameNameAreAdded() { // Arrange - var options = new MvcCacheOptions(); + var options = new MvcOptions(); options.CacheProfiles.Add("HelloWorld", new CacheProfile { Duration = 10 }); // Act & Assert diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/MvcOptionsTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/MvcOptionsTests.cs deleted file mode 100644 index 6cc4971c9b..0000000000 --- a/test/Microsoft.AspNet.Mvc.Core.Test/MvcOptionsTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -// 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.AspNet.Mvc.Core.Test -{ - public class MvcOptionsTests - { - [Fact] - public void MaxValidationError_ThrowsIfValueIsOutOfRange() - { - // Arrange - var options = new MvcOptions(); - - // Act & Assert - var ex = Assert.Throws(() => options.MaxModelValidationErrors = -1); - Assert.Equal("value", ex.ParamName); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs index 601255855f..3629472dee 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs @@ -946,9 +946,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults private static IServiceProvider GetServiceProvider() { - var optionsSetup = new MvcOptionsSetup(); var options = new MvcOptions(); - optionsSetup.Configure(options); var optionsAccessor = new Mock>(); optionsAccessor.SetupGet(o => o.Options).Returns(options); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ResponseCacheAttributeTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ResponseCacheAttributeTest.cs index 3c192b1924..a5465731bc 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ResponseCacheAttributeTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ResponseCacheAttributeTest.cs @@ -18,7 +18,8 @@ namespace Microsoft.AspNet.Mvc public void CreateInstance_SelectsTheAppropriateCacheProfile(string profileName) { // Arrange - var responseCache = new ResponseCacheAttribute() { + var responseCache = new ResponseCacheAttribute() + { CacheProfileName = profileName }; var cacheProfiles = new Dictionary(); @@ -173,29 +174,27 @@ namespace Microsoft.AspNet.Mvc cacheProfiles.Add("Test", new CacheProfile { NoStore = false }); // Act - var filter = responseCache.CreateInstance(GetServiceProvider(cacheProfiles)); + var filter = responseCache.CreateInstance(GetServiceProvider(cacheProfiles)); - // Assert - Assert.NotNull(filter); + // Assert + Assert.NotNull(filter); } private IServiceProvider GetServiceProvider(Dictionary cacheProfiles) { var serviceProvider = new Mock(); - var optionsAccessor = new Mock>(); - var options = new MvcCacheOptions(); + var optionsAccessor = new TestOptionsManager(); if (cacheProfiles != null) { foreach (var p in cacheProfiles) { - options.CacheProfiles.Add(p.Key, p.Value); + optionsAccessor.Options.CacheProfiles.Add(p.Key, p.Value); } } - optionsAccessor.SetupGet(o => o.Options).Returns(options); serviceProvider - .Setup(s => s.GetService(typeof(IOptions))) - .Returns(optionsAccessor.Object); + .Setup(s => s.GetService(typeof(IOptions))) + .Returns(optionsAccessor); return serviceProvider.Object; } diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/TestMvcOptions.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/TestMvcOptions.cs index c14efaa3c7..55c5b88954 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/TestMvcOptions.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/TestMvcOptions.cs @@ -12,9 +12,9 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public TestMvcOptions() { Options = new MvcOptions(); - CoreMvcOptionsSetup.ConfigureMvc(Options); - MvcOptionsSetup.ConfigureMvc(Options); - JsonMvcOptionsSetup.ConfigureMvc(Options, SerializerSettingsProvider.CreateSerializerSettings()); + MvcCoreMvcOptionsSetup.ConfigureMvc(Options); + MvcDataAnnotationsMvcOptionsSetup.ConfigureMvc(Options); + MvcJsonMvcOptionsSetup.ConfigureMvc(Options, SerializerSettingsProvider.CreateSerializerSettings()); } public MvcOptions Options { get; } diff --git a/test/Microsoft.AspNet.Mvc.Test/MvcOptionsSetupTest.cs b/test/Microsoft.AspNet.Mvc.Test/MvcOptionsSetupTest.cs index ccffa5bb8e..068b691f5e 100644 --- a/test/Microsoft.AspNet.Mvc.Test/MvcOptionsSetupTest.cs +++ b/test/Microsoft.AspNet.Mvc.Test/MvcOptionsSetupTest.cs @@ -7,6 +7,7 @@ using System.Xml.Linq; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.Razor; +using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.OptionsModel; using Newtonsoft.Json.Linq; using Xunit; @@ -18,62 +19,46 @@ namespace Microsoft.AspNet.Mvc [Fact] public void Setup_SetsUpViewEngines() { - // Arrange - var mvcOptions = new MvcViewOptions(); - var setup = new MvcViewOptionsSetup(); - - // Act - setup.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - Assert.Equal(1, mvcOptions.ViewEngines.Count); - Assert.Equal(typeof(RazorViewEngine), mvcOptions.ViewEngines[0].ViewEngineType); + Assert.Equal(1, options.ViewEngines.Count); + Assert.Equal(typeof(RazorViewEngine), options.ViewEngines[0].ViewEngineType); } [Fact] public void Setup_SetsUpModelBinders() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup1 = new CoreMvcOptionsSetup(); - var setup2 = new MvcOptionsSetup(); - - // Act - setup1.Configure(mvcOptions); - setup2.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert var i = 0; - Assert.Equal(13, mvcOptions.ModelBinders.Count); - Assert.IsType(typeof(BinderTypeBasedModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(ServicesModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(BodyModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(HeaderModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(TypeConverterModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(TypeMatchModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(CancellationTokenModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(ByteArrayModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(FormFileModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(FormCollectionModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(GenericModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(MutableObjectModelBinder), mvcOptions.ModelBinders[i++]); - Assert.IsType(typeof(ComplexModelDtoModelBinder), mvcOptions.ModelBinders[i++]); + Assert.Equal(13, options.ModelBinders.Count); + Assert.IsType(typeof(BinderTypeBasedModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(ServicesModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(BodyModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(HeaderModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(TypeConverterModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(TypeMatchModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(CancellationTokenModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(ByteArrayModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(FormFileModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(FormCollectionModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(GenericModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(MutableObjectModelBinder), options.ModelBinders[i++]); + Assert.IsType(typeof(ComplexModelDtoModelBinder), options.ModelBinders[i++]); } [Fact] public void Setup_SetsUpValueProviders() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup1 = new CoreMvcOptionsSetup(); - var setup2 = new MvcOptionsSetup(); - - // Act - setup1.Configure(mvcOptions); - setup2.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - var valueProviders = mvcOptions.ValueProviderFactories; + var valueProviders = options.ValueProviderFactories; Assert.Equal(3, valueProviders.Count); Assert.IsType(valueProviders[0]); Assert.IsType(valueProviders[1]); @@ -83,150 +68,111 @@ namespace Microsoft.AspNet.Mvc [Fact] public void Setup_SetsUpOutputFormatters() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup1 = new CoreMvcOptionsSetup(); - var setup2 = new MvcOptionsSetup(); - var setup3 = new JsonMvcOptionsSetup(new OptionsManager( - Enumerable.Empty>())); - - // Act - setup1.Configure(mvcOptions); - setup2.Configure(mvcOptions); - setup3.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - Assert.Equal(4, mvcOptions.OutputFormatters.Count); - Assert.IsType(mvcOptions.OutputFormatters[0]); - Assert.IsType(mvcOptions.OutputFormatters[1]); - Assert.IsType(mvcOptions.OutputFormatters[2]); - Assert.IsType(mvcOptions.OutputFormatters[3]); + Assert.Equal(4, options.OutputFormatters.Count); + Assert.IsType(options.OutputFormatters[0]); + Assert.IsType(options.OutputFormatters[1]); + Assert.IsType(options.OutputFormatters[2]); + Assert.IsType(options.OutputFormatters[3]); } [Fact] public void Setup_SetsUpInputFormatters() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup1 = new CoreMvcOptionsSetup(); - var setup2 = new MvcOptionsSetup(); - var setup3 = new JsonMvcOptionsSetup(new OptionsManager( - Enumerable.Empty>())); - - // Act - setup1.Configure(mvcOptions); - setup2.Configure(mvcOptions); - setup3.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - Assert.Equal(2, mvcOptions.InputFormatters.Count); - Assert.IsType(mvcOptions.InputFormatters[0]); - Assert.IsType(mvcOptions.InputFormatters[1]); + Assert.Equal(2, options.InputFormatters.Count); + Assert.IsType(options.InputFormatters[0]); + Assert.IsType(options.InputFormatters[1]); } [Fact] public void Setup_SetsUpModelValidatorProviders() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup1 = new CoreMvcOptionsSetup(); - var setup2 = new MvcOptionsSetup(); - - // Act - setup1.Configure(mvcOptions); - setup2.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - Assert.Equal(2, mvcOptions.ModelValidatorProviders.Count); - Assert.IsType(mvcOptions.ModelValidatorProviders[0]); - Assert.IsType(mvcOptions.ModelValidatorProviders[1]); + Assert.Equal(2, options.ModelValidatorProviders.Count); + Assert.IsType(options.ModelValidatorProviders[0]); + Assert.IsType(options.ModelValidatorProviders[1]); } [Fact] public void Setup_SetsUpClientModelValidatorProviders() { - // Arrange - var mvcOptions = new MvcViewOptions(); - var setup = new MvcViewOptionsSetup(); - - // Act - setup.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - Assert.Equal(2, mvcOptions.ClientModelValidatorProviders.Count); - Assert.IsType(mvcOptions.ClientModelValidatorProviders[0]); - Assert.IsType(mvcOptions.ClientModelValidatorProviders[1]); + Assert.Equal(2, options.ClientModelValidatorProviders.Count); + Assert.IsType(options.ClientModelValidatorProviders[0]); + Assert.IsType(options.ClientModelValidatorProviders[1]); } [Fact] public void Setup_IgnoresAcceptHeaderHavingWildCardMediaAndSubMediaTypes() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup = new CoreMvcOptionsSetup(); - - // Act - setup.Configure(mvcOptions); + // Arrange & Act + var options = GetOptions(); // Assert - Assert.False(mvcOptions.RespectBrowserAcceptHeader); + Assert.False(options.RespectBrowserAcceptHeader); } [Fact] public void Setup_SetsUpExcludeFromValidationDelegates() { - // Arrange - var mvcOptions = new MvcOptions(); - var setup1 = new CoreMvcOptionsSetup(); - var setup2 = new MvcOptionsSetup(); - - // Act - setup1.Configure(mvcOptions); - setup2.Configure(mvcOptions); - mvcOptions.AddXmlDataContractSerializerFormatter(); + // Arrange & Act + var options = GetOptions(_ => _.ConfigureMvc(o => o.AddXmlDataContractSerializerFormatter())); // Assert - Assert.Equal(8, mvcOptions.ValidationExcludeFilters.Count); + Assert.Equal(8, options.ValidationExcludeFilters.Count); var i = 0; // Verify if the delegates registered by default exclude the given types. - Assert.IsType(typeof(SimpleTypesExcludeFilter), mvcOptions.ValidationExcludeFilters[i++]); + Assert.IsType(typeof(SimpleTypesExcludeFilter), options.ValidationExcludeFilters[i++]); - Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), mvcOptions.ValidationExcludeFilters[i]); + Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), options.ValidationExcludeFilters[i]); var typeFilter - = Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + = Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(typeFilter.ExcludedType, typeof(Type)); - Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), mvcOptions.ValidationExcludeFilters[i]); + Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), options.ValidationExcludeFilters[i]); var cancellationTokenFilter - = Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + = Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(cancellationTokenFilter.ExcludedType, typeof(System.Threading.CancellationToken)); - Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), mvcOptions.ValidationExcludeFilters[i]); + Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), options.ValidationExcludeFilters[i]); var formFileFilter - = Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + = Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(formFileFilter.ExcludedType, typeof(Http.IFormFile)); Assert.IsType( typeof(DefaultTypeBasedExcludeFilter), - mvcOptions.ValidationExcludeFilters[i]); + options.ValidationExcludeFilters[i]); var formCollectionFilter - = Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + = Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(formCollectionFilter.ExcludedType, typeof(Http.IFormCollection)); - Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), mvcOptions.ValidationExcludeFilters[i]); + Assert.IsType(typeof(DefaultTypeBasedExcludeFilter), options.ValidationExcludeFilters[i]); var jTokenFilter - = Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + = Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(jTokenFilter.ExcludedType, typeof(JToken)); - Assert.IsType(typeof(DefaultTypeNameBasedExcludeFilter), mvcOptions.ValidationExcludeFilters[i]); + Assert.IsType(typeof(DefaultTypeNameBasedExcludeFilter), options.ValidationExcludeFilters[i]); var xObjectFilter - = Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + = Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(xObjectFilter.ExcludedTypeName, typeof(XObject).FullName); - Assert.IsType(typeof(DefaultTypeNameBasedExcludeFilter), mvcOptions.ValidationExcludeFilters[i]); + Assert.IsType(typeof(DefaultTypeNameBasedExcludeFilter), options.ValidationExcludeFilters[i]); var xmlNodeFilter = - Assert.IsType(mvcOptions.ValidationExcludeFilters[i++]); + Assert.IsType(options.ValidationExcludeFilters[i++]); Assert.Equal(xmlNodeFilter.ExcludedTypeName, "System.Xml.XmlNode"); } @@ -234,27 +180,45 @@ namespace Microsoft.AspNet.Mvc public void Setup_JsonFormattersUseSerializerSettings() { // Arrange - var jsonOptionsAccessor = new OptionsManager( - Enumerable.Empty>()); - - var mvcOptions = new MvcOptions(); - var setup = new JsonMvcOptionsSetup(jsonOptionsAccessor); + var services = GetServiceProvider(); // Act - setup.Configure(mvcOptions); + var options = services.GetRequiredService>().Options; + var jsonOptions = services.GetRequiredService>().Options; // Assert - var jsonInputFormatters = mvcOptions.InputFormatters.OfType(); + var jsonInputFormatters = options.InputFormatters.OfType(); foreach (var jsonInputFormatter in jsonInputFormatters) { - Assert.Same(jsonOptionsAccessor.Options.SerializerSettings, jsonInputFormatter.SerializerSettings); + Assert.Same(jsonOptions.SerializerSettings, jsonInputFormatter.SerializerSettings); } - var jsonOuputFormatters = mvcOptions.OutputFormatters.OfType(); + var jsonOuputFormatters = options.OutputFormatters.OfType(); foreach (var jsonOuputFormatter in jsonOuputFormatters) { - Assert.Same(jsonOptionsAccessor.Options.SerializerSettings, jsonOuputFormatter.SerializerSettings); + Assert.Same(jsonOptions.SerializerSettings, jsonOuputFormatter.SerializerSettings); } } + + private static T GetOptions(Action action = null) + where T : class, new() + { + var serviceProvider = GetServiceProvider(action); + return serviceProvider.GetRequiredService>().Options; + } + + private static IServiceProvider GetServiceProvider(Action action = null) + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddMvc(); + + if (action != null) + { + action(serviceCollection); + } + + var serviceProvider = serviceCollection.BuildServiceProvider(); + return serviceProvider; + } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs index 8fd50591ae..f2dfc5ae9b 100644 --- a/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Test/MvcServiceCollectionExtensionsTest.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using Microsoft.AspNet.Antiforgery; +using Microsoft.AspNet.Authorization; using Microsoft.AspNet.Mvc.ActionConstraints; using Microsoft.AspNet.Mvc.ApiExplorer; using Microsoft.AspNet.Mvc.ApplicationModels; @@ -12,6 +14,7 @@ using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.MvcServiceCollectionExtensionsTestControllers; using Microsoft.AspNet.Mvc.Razor; +using Microsoft.AspNet.Routing; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.OptionsModel; using Moq; @@ -106,7 +109,7 @@ namespace Microsoft.AspNet.Mvc } // Act - MvcServiceCollectionExtensions.AddMvcServices(services); + services.AddMvc(); // Assert foreach (var serviceType in MutliRegistrationServiceTypes) @@ -134,7 +137,7 @@ namespace Microsoft.AspNet.Mvc } // Act - MvcServiceCollectionExtensions.AddMvcServices(services); + services.AddMvc(); // Assert foreach (var singleRegistrationType in SingleRegistrationServiceTypes) @@ -150,8 +153,8 @@ namespace Microsoft.AspNet.Mvc var services = new ServiceCollection(); // Act - MvcServiceCollectionExtensions.AddMvcServices(services); - MvcServiceCollectionExtensions.AddMvcServices(services); + services.AddMvc(); + services.AddMvc(); // Assert var singleRegistrationServiceTypes = SingleRegistrationServiceTypes; @@ -162,6 +165,10 @@ namespace Microsoft.AspNet.Mvc // 'single-registration' services should only have one implementation registered. AssertServiceCountEquals(services, service.ServiceType, 1); } + else if (service.ImplementationType != null && !service.ImplementationType.Assembly.FullName.Contains("Mvc")) + { + // Ignore types that don't come from MVC + } else { // 'multi-registration' services should only have one *instance* of each implementation registered. @@ -175,11 +182,12 @@ namespace Microsoft.AspNet.Mvc get { var services = new ServiceCollection(); - MvcServiceCollectionExtensions.AddMvcServices(services); + services.AddMvc(); var multiRegistrationServiceTypes = MutliRegistrationServiceTypes; return services .Where(sd => !multiRegistrationServiceTypes.Keys.Contains(sd.ServiceType)) + .Where(sd => sd.ServiceType.Assembly.FullName.Contains("Mvc")) .Select(sd => sd.ServiceType); } } @@ -194,15 +202,16 @@ namespace Microsoft.AspNet.Mvc typeof(IConfigureOptions), new Type[] { - typeof(MvcOptionsSetup), - typeof(JsonMvcOptionsSetup), + typeof(MvcCoreMvcOptionsSetup), + typeof(MvcDataAnnotationsMvcOptionsSetup), + typeof(MvcJsonMvcOptionsSetup), } }, { - typeof(IConfigureOptions), + typeof(IConfigureOptions), new Type[] { - typeof(JsonMvcFormatterMappingOptionsSetup), + typeof(MvcCoreRouteOptionsSetup), } }, { @@ -210,6 +219,7 @@ namespace Microsoft.AspNet.Mvc new Type[] { typeof(MvcViewOptionsSetup), + typeof(MvcRazorMvcViewOptionsSetup), } }, { @@ -219,17 +229,39 @@ namespace Microsoft.AspNet.Mvc typeof(RazorViewEngineOptionsSetup), } }, - { - typeof(IApiDescriptionProvider), + { + typeof(IActionConstraintProvider), new Type[] { - typeof(DefaultApiDescriptionProvider), + typeof(DefaultActionConstraintProvider), + } + }, + { + typeof(IActionDescriptorProvider), + new Type[] + { + typeof(ControllerActionDescriptorProvider), + } + }, + { + typeof(IActionInvokerProvider), + new Type[] + { + typeof(ControllerActionInvokerProvider), + } + }, + { + typeof(IFilterProvider), + new Type[] + { + typeof(DefaultFilterProvider), } }, { typeof(IControllerPropertyActivator), new Type[] { + typeof(DefaultControllerPropertyActivator), typeof(ViewDataDictionaryControllerPropertyActivator), } }, @@ -237,10 +269,18 @@ namespace Microsoft.AspNet.Mvc typeof(IApplicationModelProvider), new Type[] { + typeof(DefaultApplicationModelProvider), typeof(CorsApplicationModelProvider), typeof(AuthorizationApplicationModelProvider), } }, + { + typeof(IApiDescriptionProvider), + new Type[] + { + typeof(DefaultApiDescriptionProvider), + } + }, }; } } diff --git a/test/Microsoft.AspNet.Mvc.Test/project.json b/test/Microsoft.AspNet.Mvc.Test/project.json index 3b3519496f..e9c837936e 100644 --- a/test/Microsoft.AspNet.Mvc.Test/project.json +++ b/test/Microsoft.AspNet.Mvc.Test/project.json @@ -5,6 +5,7 @@ "dependencies": { "Microsoft.AspNet.Mvc": "6.0.0-*", "Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-*", + "Microsoft.Framework.DependencyInjection": "1.0.0-*", "xunit.runner.aspnet": "2.0.0-aspnet-*" }, "commands": { diff --git a/test/WebSites/FormatFilterWebSite/Startup.cs b/test/WebSites/FormatFilterWebSite/Startup.cs index bf03de53a5..af45536a55 100644 --- a/test/WebSites/FormatFilterWebSite/Startup.cs +++ b/test/WebSites/FormatFilterWebSite/Startup.cs @@ -24,7 +24,7 @@ namespace FormatFilterWebSite var customFormatter = new CustomFormatter("application/custom"); options.OutputFormatters.Add(customFormatter); }); - services.ConfigureMvcFormatterMappings(options => + services.ConfigureMvc(options => { options.FormatterMappings.SetMediaTypeMappingForFormat( "custom", diff --git a/test/WebSites/ResponseCacheWebSite/Startup.cs b/test/WebSites/ResponseCacheWebSite/Startup.cs index 7a385924e8..a3bf0d01c6 100644 --- a/test/WebSites/ResponseCacheWebSite/Startup.cs +++ b/test/WebSites/ResponseCacheWebSite/Startup.cs @@ -13,7 +13,7 @@ namespace ResponseCacheWebSite public void ConfigureServices(IServiceCollection services) { services.AddMvc(); - services.ConfigureMvcCaching(options => + services.ConfigureMvc(options => { options.CacheProfiles.Add( "PublicCache30Sec", new CacheProfile