Tweak lifetimes for a few commonly resolved services
This is some low hanging fruit for reducing the number of resolves we have per request. DefaultHtmlGenerator: Lots of these are created by RazorPage. It needs IUrlHelper, so scoped is the best we can do for now. For an example, on the front page of our sample, 48 of these are created for each request. 48! This takes it down to 1-per-request. JsonResult: Again, multiple created per request (12 for the sample). This class is totally stateless, so we can get down to 0-per-request. DefaultViewComponentInvokerFactory: Same story as JsonResult. DefaultObjectValidator/MvcMarkerService/DefaultFilterProvider: these are stateless and pretty much guaranteed to be used by every request. Getting them off the table.
This commit is contained in:
parent
08068a85be
commit
d2908e7b7b
|
|
@ -2,13 +2,10 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
|
|
|
|||
|
|
@ -10,18 +10,11 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
{
|
||||
public class DefaultFilterProvider : IFilterProvider
|
||||
{
|
||||
public DefaultFilterProvider(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public int Order
|
||||
{
|
||||
get { return DefaultOrder.DefaultFrameworkSortOrder; }
|
||||
}
|
||||
|
||||
protected IServiceProvider ServiceProvider { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnProvidersExecuting([NotNull] FilterProviderContext context)
|
||||
{
|
||||
|
|
@ -55,7 +48,8 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
}
|
||||
else
|
||||
{
|
||||
filterItem.Filter = filterFactory.CreateInstance(ServiceProvider);
|
||||
var services = context.ActionContext.HttpContext.RequestServices;
|
||||
filterItem.Filter = filterFactory.CreateInstance(services);
|
||||
|
||||
if (filterItem.Filter == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -88,13 +88,15 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
//
|
||||
// Action Invoker
|
||||
//
|
||||
// This accesses per-request services
|
||||
// These two access per-request services
|
||||
services.TryAddTransient<IActionInvokerFactory, ActionInvokerFactory>();
|
||||
services.TryAddTransient<IControllerActionArgumentBinder, DefaultControllerActionArgumentBinder>();
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IActionInvokerProvider, ControllerActionInvokerProvider>());
|
||||
|
||||
// These are stateless
|
||||
services.TryAddSingleton<IControllerActionArgumentBinder, DefaultControllerActionArgumentBinder>();
|
||||
services.TryAddEnumerable(
|
||||
ServiceDescriptor.Transient<IFilterProvider, DefaultFilterProvider>());
|
||||
ServiceDescriptor.Singleton<IFilterProvider, DefaultFilterProvider>());
|
||||
|
||||
//
|
||||
// ModelBinding, Validation and Formatting
|
||||
|
|
@ -106,7 +108,7 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
var options = serviceProvider.GetRequiredService<IOptions<MvcOptions>>().Options;
|
||||
return new DefaultCompositeMetadataDetailsProvider(options.ModelMetadataDetailsProviders);
|
||||
}));
|
||||
services.TryAdd(ServiceDescriptor.Transient<IObjectModelValidator>(serviceProvider =>
|
||||
services.TryAdd(ServiceDescriptor.Singleton<IObjectModelValidator>(serviceProvider =>
|
||||
{
|
||||
var options = serviceProvider.GetRequiredService<IOptions<MvcOptions>>().Options;
|
||||
var modelMetadataProvider = serviceProvider.GetRequiredService<IModelMetadataProvider>();
|
||||
|
|
@ -125,7 +127,7 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
//
|
||||
// Random Infrastructure
|
||||
//
|
||||
services.TryAddTransient<MvcMarkerService, MvcMarkerService>();
|
||||
services.TryAddSingleton<MvcMarkerService, MvcMarkerService>();
|
||||
services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>();
|
||||
services.TryAddScoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>));
|
||||
services.TryAddScoped<IUrlHelper, UrlHelper>();
|
||||
|
|
@ -141,4 +143,4 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
ServiceDescriptor.Transient<IConfigureOptions<RouteOptions>, MvcRouteOptionsSetup>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -132,14 +132,15 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
[NotNull] ViewComponentDescriptor descriptor,
|
||||
object[] arguments)
|
||||
{
|
||||
var invoker = _invokerFactory.CreateInstance(descriptor, arguments);
|
||||
var context = new ViewComponentContext(descriptor, arguments, _viewContext, writer);
|
||||
|
||||
var invoker = _invokerFactory.CreateInstance(context);
|
||||
if (invoker == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.Type.FullName));
|
||||
}
|
||||
|
||||
var context = new ViewComponentContext(descriptor, arguments, _viewContext, writer);
|
||||
await invoker.InvokeAsync(context);
|
||||
}
|
||||
|
||||
|
|
@ -148,14 +149,15 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
[NotNull] ViewComponentDescriptor descriptor,
|
||||
object[] arguments)
|
||||
{
|
||||
var invoker = _invokerFactory.CreateInstance(descriptor, arguments);
|
||||
var context = new ViewComponentContext(descriptor, arguments, _viewContext, writer);
|
||||
|
||||
var invoker = _invokerFactory.CreateInstance(context);
|
||||
if (invoker == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
Resources.FormatViewComponent_IViewComponentFactory_ReturnedNull(descriptor.Type.FullName));
|
||||
}
|
||||
|
||||
var context = new ViewComponentContext(descriptor, arguments, _viewContext, writer);
|
||||
invoker.Invoke(context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,16 +13,13 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
{
|
||||
public class DefaultViewComponentInvoker : IViewComponentInvoker
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
|
||||
public DefaultViewComponentInvoker(
|
||||
[NotNull] IServiceProvider serviceProvider,
|
||||
[NotNull] ITypeActivatorCache typeActivatorCache,
|
||||
[NotNull] IViewComponentActivator viewComponentActivator)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
}
|
||||
|
|
@ -77,8 +74,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
|
||||
private object CreateComponent([NotNull] ViewComponentContext context)
|
||||
{
|
||||
var services = context.ViewContext.HttpContext.RequestServices;
|
||||
var component = _typeActivatorCache.CreateInstance<object>(
|
||||
_serviceProvider,
|
||||
services,
|
||||
context.ViewComponentDescriptor.Type);
|
||||
_viewComponentActivator.Activate(component, context);
|
||||
return component;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,19 @@
|
|||
// 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.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewComponents
|
||||
{
|
||||
public class DefaultViewComponentInvokerFactory : IViewComponentInvokerFactory
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITypeActivatorCache _typeActivatorCache;
|
||||
private readonly IViewComponentActivator _viewComponentActivator;
|
||||
|
||||
public DefaultViewComponentInvokerFactory(
|
||||
IServiceProvider serviceProvider,
|
||||
ITypeActivatorCache typeActivatorCache,
|
||||
IViewComponentActivator viewComponentActivator)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_typeActivatorCache = typeActivatorCache;
|
||||
_viewComponentActivator = viewComponentActivator;
|
||||
}
|
||||
|
|
@ -26,12 +22,9 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
// We don't currently make use of the descriptor or the arguments here (they are available on the context).
|
||||
// We might do this some day to cache which method we select, so resist the urge to 'clean' this without
|
||||
// considering that possibility.
|
||||
public IViewComponentInvoker CreateInstance(
|
||||
[NotNull] ViewComponentDescriptor viewComponentDescriptor,
|
||||
object[] args)
|
||||
public IViewComponentInvoker CreateInstance([NotNull] ViewComponentContext context)
|
||||
{
|
||||
return new DefaultViewComponentInvoker(
|
||||
_serviceProvider,
|
||||
_typeActivatorCache,
|
||||
_viewComponentActivator);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ namespace Microsoft.AspNet.Mvc.ViewComponents
|
|||
{
|
||||
public interface IViewComponentInvokerFactory
|
||||
{
|
||||
IViewComponentInvoker CreateInstance(
|
||||
[NotNull] ViewComponentDescriptor viewComponentDescriptor,
|
||||
object[] args);
|
||||
IViewComponentInvoker CreateInstance([NotNull] ViewComponentContext context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
// View and rendering helpers
|
||||
services.TryAddTransient<IHtmlHelper, HtmlHelper>();
|
||||
services.TryAddTransient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>));
|
||||
services.TryAddTransient<IJsonHelper, JsonHelper>();
|
||||
services.TryAddSingleton<IJsonHelper, JsonHelper>();
|
||||
|
||||
// Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict.
|
||||
services.TryAddSingleton<ITagHelperActivator, DefaultTagHelperActivator>();
|
||||
|
|
@ -230,9 +230,9 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
// Consumed by the Cache tag helper to cache results across the lifetime of the application.
|
||||
services.TryAddSingleton<IMemoryCache, MemoryCache>();
|
||||
|
||||
// DefaultHtmlGenerator is pretty much stateless but depends on Scoped services such as IUrlHelper and
|
||||
// IActionBindingContextProvider. Therefore it too is scoped.
|
||||
services.TryAddTransient<IHtmlGenerator, DefaultHtmlGenerator>();
|
||||
// DefaultHtmlGenerator is pretty much stateless but depends on IUrlHelper, which is scoped.
|
||||
// Therefore it too is scoped.
|
||||
services.TryAddScoped<IHtmlGenerator, DefaultHtmlGenerator>();
|
||||
|
||||
// These do caching so they should stay singleton
|
||||
services.TryAddSingleton<IViewComponentSelector, DefaultViewComponentSelector>();
|
||||
|
|
@ -242,7 +242,7 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
DefaultViewComponentDescriptorCollectionProvider>();
|
||||
|
||||
services.TryAddTransient<IViewComponentDescriptorProvider, DefaultViewComponentDescriptorProvider>();
|
||||
services.TryAddTransient<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
||||
services.TryAddSingleton<IViewComponentInvokerFactory, DefaultViewComponentInvokerFactory>();
|
||||
services.TryAddTransient<IViewComponentHelper, DefaultViewComponentHelper>();
|
||||
|
||||
// Security and Authorization
|
||||
|
|
@ -292,4 +292,4 @@ namespace Microsoft.Framework.DependencyInjection
|
|||
services.AddWebEncoders();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,9 +137,7 @@ namespace Microsoft.AspNet.Mvc.Filters
|
|||
|
||||
private DefaultFilterProvider CreateProvider()
|
||||
{
|
||||
var services = new ServiceContainer();
|
||||
|
||||
return new DefaultFilterProvider(services);
|
||||
return new DefaultFilterProvider();
|
||||
}
|
||||
|
||||
private FilterProviderContext CreateFilterContext(List<FilterItem> items)
|
||||
|
|
|
|||
Loading…
Reference in New Issue