// 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.Actions; using Microsoft.AspNet.Mvc.ApplicationModels; 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.DependencyInjection.Extensions; using Microsoft.Framework.Internal; using Microsoft.Framework.OptionsModel; namespace Microsoft.Framework.DependencyInjection { public static class MvcCoreServiceCollectionExtensions { public static IMvcCoreBuilder AddMvcCore([NotNull] this IServiceCollection services) { return AddMvcCore(services, setupAction: null); } public static IMvcCoreBuilder AddMvcCore( [NotNull] this IServiceCollection services, Action setupAction) { ConfigureDefaultServices(services); AddMvcCoreServices(services); if (setupAction != null) { services.Configure(setupAction); } return new MvcCoreBuilder(services); } // To enable unit testing internal static void AddMvcCoreServices(IServiceCollection services) { // // Options // services.TryAddEnumerable( ServiceDescriptor.Transient, MvcCoreMvcOptionsSetup>()); services.TryAddEnumerable( ServiceDescriptor.Transient, MvcCoreRouteOptionsSetup>()); // // 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 // // The IActionInvokerFactory is cachable services.TryAddSingleton(); services.TryAddEnumerable( ServiceDescriptor.Transient()); // These are stateless services.TryAddSingleton(); services.TryAddEnumerable( ServiceDescriptor.Singleton()); // // 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>().Value; return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders); })); services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => { var options = serviceProvider.GetRequiredService>().Value; var modelMetadataProvider = serviceProvider.GetRequiredService(); return new DefaultObjectValidator(options.ValidationExcludeFilters, modelMetadataProvider); })); // // Random Infrastructure // services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); } private static void ConfigureDefaultServices(IServiceCollection services) { services.AddOptions(); services.AddRouting(); services.AddNotifier(); } } }