Register default services directly in AddMvc and remove MvcServices

This commit is contained in:
Kiran Challa 2015-04-30 15:01:05 -07:00
parent f37f2ae352
commit 284c899233
3 changed files with 173 additions and 179 deletions

View File

@ -6,8 +6,25 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ActionConstraints;
using Microsoft.AspNet.Mvc.ApiExplorer;
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.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewComponents;
using Microsoft.AspNet.Routing;
using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.Internal;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.Framework.DependencyInjection
{
@ -16,7 +33,158 @@ namespace Microsoft.Framework.DependencyInjection
public static IServiceCollection AddMvc([NotNull] this IServiceCollection services)
{
ConfigureDefaultServices(services);
services.TryAdd(MvcServices.GetDefaultServices());
// Options and core services.
services.TryAdd(ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcOptionsSetup>());
services.TryAdd(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
services.TryAdd(ServiceDescriptor.Transient<IAssemblyProvider, DefaultAssemblyProvider>());
services.TryAdd(ServiceDescriptor.Transient<MvcMarkerService, MvcMarkerService>());
services.TryAdd((ServiceDescriptor.Singleton<ITypeActivatorCache, DefaultTypeActivatorCache>()));
services.TryAdd(ServiceDescriptor.Scoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>)));
// Core action discovery, filters and action execution.
// These are consumed only when creating action descriptors, then they can be de-allocated
services.TryAdd(ServiceDescriptor.Transient<IControllerTypeProvider, DefaultControllerTypeProvider>());
services.TryAdd(ServiceDescriptor.Transient<IControllerModelBuilder, DefaultControllerModelBuilder>());
services.TryAdd(ServiceDescriptor.Transient<IActionModelBuilder, DefaultActionModelBuilder>());
// This has a cache, so it needs to be a singleton
services.TryAdd(ServiceDescriptor.Singleton<IControllerFactory, DefaultControllerFactory>());
services.TryAdd(ServiceDescriptor.Transient<IControllerActivator, DefaultControllerActivator>());
// This accesses per-request services
services.TryAdd(ServiceDescriptor.Transient<IActionInvokerFactory, ActionInvokerFactory>());
// This provider needs access to the per-request services, but might be used many times for a given
// request.
services.TryAdd(ServiceDescriptor.Transient<IActionConstraintProvider, DefaultActionConstraintProvider>());
services.TryAdd(ServiceDescriptor
.Singleton<IActionSelectorDecisionTreeProvider, ActionSelectorDecisionTreeProvider>());
services.TryAdd(ServiceDescriptor.Singleton<IActionSelector, DefaultActionSelector>());
services.TryAdd(ServiceDescriptor
.Transient<IControllerActionArgumentBinder, DefaultControllerActionArgumentBinder>());
services.TryAdd(ServiceDescriptor.Transient<IObjectModelValidator>(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<MvcOptions>>().Options;
var modelMetadataProvider = serviceProvider.GetRequiredService<IModelMetadataProvider>();
return new DefaultObjectValidator(options.ValidationExcludeFilters, modelMetadataProvider);
}));
services.TryAdd(ServiceDescriptor
.Transient<IActionDescriptorProvider, ControllerActionDescriptorProvider>());
services.TryAdd(ServiceDescriptor.Transient<IActionInvokerProvider, ControllerActionInvokerProvider>());
services.TryAdd(ServiceDescriptor
.Singleton<IActionDescriptorsCollectionProvider, DefaultActionDescriptorsCollectionProvider>());
// The IGlobalFilterProvider is used to build the action descriptors (likely once) and so should
// remain transient to avoid keeping it in memory.
services.TryAdd(ServiceDescriptor.Transient<IGlobalFilterProvider, DefaultGlobalFilterProvider>());
services.TryAdd(ServiceDescriptor.Transient<IFilterProvider, DefaultFilterProvider>());
services.TryAdd(ServiceDescriptor.Transient<FormatFilter, FormatFilter>());
services.TryAdd(ServiceDescriptor.Transient<CorsAuthorizationFilter, CorsAuthorizationFilter>());
// Dataflow - ModelBinding, Validation and Formatting
//
// The DefaultModelMetadataProvider does significant caching and should be a singleton.
services.TryAdd(ServiceDescriptor.Singleton<IModelMetadataProvider, DefaultModelMetadataProvider>());
services.TryAdd(ServiceDescriptor.Transient<ICompositeMetadataDetailsProvider>(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<MvcOptions>>().Options;
return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders);
}));
services.TryAdd(ServiceDescriptor.Instance(typeof(JsonOutputFormatter), new JsonOutputFormatter()));
// Razor, Views and runtime compilation
// The provider is inexpensive to initialize and provides ViewEngines that may require request
// specific services.
services.TryAdd(ServiceDescriptor.Scoped<ICompositeViewEngine, CompositeViewEngine>());
// Caches view locations that are valid for the lifetime of the application.
services.TryAdd(ServiceDescriptor.Singleton<IViewLocationCache, DefaultViewLocationCache>());
services.TryAdd(ServiceDescriptor.Singleton<ICodeTreeCache>(serviceProvider =>
{
var cachedFileProvider = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>();
return new DefaultCodeTreeCache(cachedFileProvider.Options.FileProvider);
}));
// The host is designed to be discarded after consumption and is very inexpensive to initialize.
services.TryAdd(ServiceDescriptor.Transient<IMvcRazorHost, MvcRazorHost>());
// Caches compilation artifacts across the lifetime of the application.
services.TryAdd(ServiceDescriptor.Singleton<ICompilerCache, CompilerCache>());
// This caches compilation related details that are valid across the lifetime of the application
// and is required to be a singleton.
services.TryAdd(ServiceDescriptor.Singleton<ICompilationService, RoslynCompilationService>());
// 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.TryAdd(ServiceDescriptor.Transient<IRazorCompilationService, RazorCompilationService>());
// The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory
services.TryAdd(ServiceDescriptor.Scoped<IViewStartProvider, ViewStartProvider>());
services.TryAdd(ServiceDescriptor.Transient<IRazorViewFactory, RazorViewFactory>());
services.TryAdd(ServiceDescriptor.Singleton<IRazorPageActivator, RazorPageActivator>());
// Virtual path view factory needs to stay scoped so views can get get scoped services.
services.TryAdd(ServiceDescriptor.Scoped<IRazorPageFactory, VirtualPathRazorPageFactory>());
// View and rendering helpers
services.TryAdd(ServiceDescriptor.Transient<IHtmlHelper, HtmlHelper>());
services.TryAdd(ServiceDescriptor.Transient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)));
services.TryAdd(ServiceDescriptor.Scoped<IUrlHelper, UrlHelper>());
// Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict.
services.TryAdd(ServiceDescriptor.Singleton<ITagHelperActivator, DefaultTagHelperActivator>());
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
services.TryAdd(ServiceDescriptor.Singleton<IMemoryCache, MemoryCache>());
// DefaultHtmlGenerator is pretty much stateless but depends on Scoped services such as IUrlHelper and
// IActionBindingContextProvider. Therefore it too is scoped.
services.TryAdd(ServiceDescriptor.Transient<IHtmlGenerator, DefaultHtmlGenerator>());
// These do caching so they should stay singleton
services.TryAdd(ServiceDescriptor.Singleton<IViewComponentSelector, DefaultViewComponentSelector>());
services.TryAdd(ServiceDescriptor.Singleton<IViewComponentActivator, DefaultViewComponentActivator>());
services.TryAdd(ServiceDescriptor.Singleton<
IViewComponentDescriptorCollectionProvider,
DefaultViewComponentDescriptorCollectionProvider>());
services.TryAdd(ServiceDescriptor
.Transient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>());
services.TryAdd(ServiceDescriptor
.Transient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>());
services.TryAdd(ServiceDescriptor.Transient<IViewComponentHelper, DefaultViewComponentHelper>());
// Security and Authorization
services.TryAdd(ServiceDescriptor.Singleton<IClaimUidExtractor, DefaultClaimUidExtractor>());
services.TryAdd(ServiceDescriptor.Singleton<AntiForgery, AntiForgery>());
services.TryAdd(ServiceDescriptor
.Singleton<IAntiForgeryAdditionalDataProvider, DefaultAntiForgeryAdditionalDataProvider>());
// Api Description
services.TryAdd(ServiceDescriptor
.Singleton<IApiDescriptionGroupCollectionProvider, ApiDescriptionGroupCollectionProvider>());
services.TryAdd(ServiceDescriptor.Transient<IApiDescriptionProvider, DefaultApiDescriptionProvider>());
// Temp Data
services.TryAdd(ServiceDescriptor.Scoped<ITempDataDictionary, TempDataDictionary>());
// This does caching so it should stay singleton
services.TryAdd(ServiceDescriptor.Singleton<ITempDataProvider, SessionStateTempDataProvider>());
return services;
}
@ -47,7 +215,7 @@ namespace Microsoft.Framework.DependencyInjection
var controllerTypeProvider = new FixedSetControllerTypeProvider();
foreach (var type in controllerTypes)
{
services.AddTransient(type);
services.TryAdd(ServiceDescriptor.Transient(type, type));
controllerTypeProvider.ControllerTypes.Add(type.GetTypeInfo());
}

View File

@ -1,176 +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.AspNet.Mvc.ActionConstraints;
using Microsoft.AspNet.Mvc.ApiExplorer;
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.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.Directives;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewComponents;
using Microsoft.Framework.Caching.Memory;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
namespace Microsoft.AspNet.Mvc
{
public class MvcServices
{
public static IServiceCollection GetDefaultServices()
{
var services = new ServiceCollection();
// Options and core services.
services.AddTransient<IConfigureOptions<MvcOptions>, MvcOptionsSetup>();
services.AddTransient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>();
// TryAdd() so functional tests can override this particular service. Test setup runs before this method.
services.TryAdd(ServiceDescriptor.Transient<IAssemblyProvider, DefaultAssemblyProvider>());
services.AddTransient<MvcMarkerService, MvcMarkerService>();
services.AddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>();
services.AddScoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>));
// Core action discovery, filters and action execution.
// These are consumed only when creating action descriptors, then they can be de-allocated
services.AddTransient<IControllerTypeProvider, DefaultControllerTypeProvider>();
services.AddTransient<IControllerModelBuilder, DefaultControllerModelBuilder>();
services.AddTransient<IActionModelBuilder, DefaultActionModelBuilder>();
// This has a cache, so it needs to be a singleton
services.AddSingleton<IControllerFactory, DefaultControllerFactory>();
services.AddTransient<IControllerActivator, DefaultControllerActivator>();
// This accesses per-reqest services
services.AddTransient<IActionInvokerFactory, ActionInvokerFactory>();
// This provider needs access to the per-request services, but might be used many times for a given
// request.
services.AddTransient<IActionConstraintProvider, DefaultActionConstraintProvider>();
services.AddSingleton<IActionSelectorDecisionTreeProvider, ActionSelectorDecisionTreeProvider>();
services.AddSingleton<IActionSelector, DefaultActionSelector>();
services.AddTransient<IControllerActionArgumentBinder, DefaultControllerActionArgumentBinder>();
services.AddTransient<IObjectModelValidator>(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<MvcOptions>>().Options;
var modelMetadataProvider = serviceProvider.GetRequiredService<IModelMetadataProvider>();
return new DefaultObjectValidator(options.ValidationExcludeFilters, modelMetadataProvider);
});
services.AddTransient<IActionDescriptorProvider, ControllerActionDescriptorProvider>();
services.AddTransient<IActionInvokerProvider, ControllerActionInvokerProvider>();
services.AddSingleton<IActionDescriptorsCollectionProvider, DefaultActionDescriptorsCollectionProvider>();
// The IGlobalFilterProvider is used to build the action descriptors (likely once) and so should
// remain transient to avoid keeping it in memory.
services.AddTransient<IGlobalFilterProvider, DefaultGlobalFilterProvider>();
services.AddTransient<IFilterProvider, DefaultFilterProvider>();
services.AddTransient<FormatFilter, FormatFilter>();
services.AddTransient<CorsAuthorizationFilter, CorsAuthorizationFilter>();
// Dataflow - ModelBinding, Validation and Formatting
//
// The DefaultModelMetadataProvider does significant caching and should be a singleton.
services.AddSingleton<IModelMetadataProvider, DefaultModelMetadataProvider>();
services.AddTransient<ICompositeMetadataDetailsProvider>(serviceProvider =>
{
var options = serviceProvider.GetRequiredService<IOptions<MvcOptions>>().Options;
return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders);
});
services.AddInstance(new JsonOutputFormatter());
// Razor, Views and runtime compilation
// The provider is inexpensive to initialize and provides ViewEngines that may require request
// specific services.
services.AddScoped<ICompositeViewEngine, CompositeViewEngine>();
// Caches view locations that are valid for the lifetime of the application.
services.AddSingleton<IViewLocationCache, DefaultViewLocationCache>();
services.AddSingleton<ICodeTreeCache>(serviceProvider =>
{
var cachedFileProvider = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>();
return new DefaultCodeTreeCache(cachedFileProvider.Options.FileProvider);
});
// The host is designed to be discarded after consumption and is very inexpensive to initialize.
services.AddTransient<IMvcRazorHost, MvcRazorHost>();
// Caches compilation artifacts across the lifetime of the application.
services.AddSingleton<ICompilerCache, CompilerCache>();
// This caches compilation related details that are valid across the lifetime of the application
// and is required to be a singleton.
services.AddSingleton<ICompilationService, RoslynCompilationService>();
// 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.AddTransient<IRazorCompilationService, RazorCompilationService>();
// The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory
services.AddScoped<IViewStartProvider, ViewStartProvider>();
services.AddTransient<IRazorViewFactory, RazorViewFactory>();
services.AddSingleton<IRazorPageActivator, RazorPageActivator>();
// Virtual path view factory needs to stay scoped so views can get get scoped services.
services.AddScoped<IRazorPageFactory, VirtualPathRazorPageFactory>();
// View and rendering helpers
services.AddTransient<IHtmlHelper, HtmlHelper>();
services.AddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>));
services.AddScoped<IUrlHelper, UrlHelper>();
// Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict.
services.AddSingleton<ITagHelperActivator, DefaultTagHelperActivator>();
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
services.AddSingleton<IMemoryCache, MemoryCache>();
// DefaultHtmlGenerator is pretty much stateless but depends on Scoped services such as IUrlHelper and
// IActionBindingContextProvider. Therefore it too is scoped.
services.AddTransient<IHtmlGenerator, DefaultHtmlGenerator>();
// These do caching so they should stay singleton
services.AddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
services.AddSingleton<IViewComponentActivator, DefaultViewComponentActivator>();
services.AddSingleton<IViewComponentDescriptorCollectionProvider,
DefaultViewComponentDescriptorCollectionProvider>();
services.AddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
services.AddTransient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
services.AddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
// Security and Authorization
services.AddSingleton<IClaimUidExtractor, DefaultClaimUidExtractor>();
services.AddSingleton<AntiForgery, AntiForgery>();
services.AddSingleton<IAntiForgeryAdditionalDataProvider, DefaultAntiForgeryAdditionalDataProvider>();
// Api Description
services.AddSingleton<IApiDescriptionGroupCollectionProvider, ApiDescriptionGroupCollectionProvider>();
services.AddTransient<IApiDescriptionProvider, DefaultApiDescriptionProvider>();
// Temp Data
services.AddScoped<ITempDataDictionary, TempDataDictionary>();
// This does caching so it should stay singleton
services.AddSingleton<ITempDataProvider, SessionStateTempDataProvider>();
return services;
}
}
}

View File

@ -61,7 +61,9 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
private static void InitializeServices(HttpContext httpContext, Action<MvcOptions> updateOptions = null)
{
var serviceCollection = MvcServices.GetDefaultServices();
var serviceCollection = new ServiceCollection();
serviceCollection.AddMvc();
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
var actionContext = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor());