// 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.ActionConstraints; using Microsoft.AspNet.Mvc.ApplicationModels; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Metadata; using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Routing; using Microsoft.Framework.Internal; using Microsoft.Framework.OptionsModel; namespace Microsoft.Framework.DependencyInjection { public static class MvcCoreServiceCollectionExtensions { public static IServiceCollection AddMinimalMvc([NotNull] this IServiceCollection services) { ConfigureDefaultServices(services); AddMvcCoreServices(services); return services; } /// /// Configures a set of for the application. /// /// The services available in the application. /// The which need to be configured. public static void ConfigureMvc( [NotNull] this IServiceCollection services, [NotNull] Action setupAction) { services.Configure(setupAction); } // To enable unit testing internal static void AddMvcCoreServices(IServiceCollection services) { // // Options // services.TryAddEnumerable( ServiceDescriptor.Transient, CoreMvcOptionsSetup>()); // // Action Discovery // // These are consumed only when creating action descriptors, then they can be de-allocated services.TryAddTransient(); services.TryAddTransient(); services.TryAddEnumerable( ServiceDescriptor.Transient()); services.TryAddEnumerable( ServiceDescriptor.Transient()); services.TryAddSingleton(); // // Action Selection // services.TryAddSingleton(); // Performs caching services.TryAddSingleton(); // Will be cached by the DefaultActionSelector services.TryAddEnumerable( ServiceDescriptor.Transient()); // // Controller Factory // // This has a cache, so it needs to be a singleton services.TryAddSingleton(); // Will be cached by the DefaultControllerFactory services.TryAddTransient(); services.TryAddEnumerable( ServiceDescriptor.Transient()); // // Action Invoker // // This accesses per-request services services.TryAddTransient(); services.TryAddTransient(); services.TryAddEnumerable( ServiceDescriptor.Transient()); services.TryAddEnumerable( ServiceDescriptor.Transient()); // // ModelBinding, Validation and Formatting // // The DefaultModelMetadataProvider does significant caching and should be a singleton. services.TryAddSingleton(); services.TryAdd(ServiceDescriptor.Transient(serviceProvider => { var options = serviceProvider.GetRequiredService>().Options; return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders); })); services.TryAdd(ServiceDescriptor.Transient(serviceProvider => { var options = serviceProvider.GetRequiredService>().Options; var modelMetadataProvider = serviceProvider.GetRequiredService(); return new DefaultObjectValidator(options.ValidationExcludeFilters, modelMetadataProvider); })); // // Temp Data // // Holds per-request data so it should be scoped services.TryAddScoped(); // This does caching so it should stay singleton services.TryAddSingleton(); // // Random Infrastructure // services.TryAddTransient(); services.TryAddSingleton(); services.TryAddScoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>)); services.TryAddScoped(); } private static void ConfigureDefaultServices(IServiceCollection services) { services.AddOptions(); services.AddRouting(); services.AddNotifier(); services.TryAddEnumerable( ServiceDescriptor.Transient, MvcRouteOptionsSetup>()); } } }