Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

Commit

Permalink
Use factory pattern for caching in ControllerActionInvoker
Browse files Browse the repository at this point in the history
  • Loading branch information
pranavkm committed May 15, 2017
1 parent cf47427 commit 37f7e72
Show file tree
Hide file tree
Showing 30 changed files with 1,624 additions and 344 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// 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.Reflection;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Mvc.Controllers
{
/// <summary>
/// Provides methods to create an MVC controller.
/// </summary>
public class ControllerActivatorProvider : IControllerActivatorProvider
{
private static readonly Func<Type, ObjectFactory> _createFactory = (type) => ActivatorUtilities.CreateFactory(type, Type.EmptyTypes);
private static readonly Action<ControllerContext, object> _dispose = Dispose;
private readonly Func<ControllerContext, object> _controllerActivatorCreate;
private readonly Action<ControllerContext, object> _controllerActivatorRelease;

public ControllerActivatorProvider(IControllerActivator controllerActivator)
{
if (controllerActivator == null)
{
throw new ArgumentNullException(nameof(controllerActivator));
}

// Compat: Delegate to controllerActivator if it's not the default implementation.
if (controllerActivator.GetType() != typeof(DefaultControllerActivator))
{
_controllerActivatorCreate = controllerActivator.Create;
_controllerActivatorRelease = controllerActivator.Release;
}
}

public Func<ControllerContext, object> CreateActivator(ControllerActionDescriptor descriptor)
{
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

var controllerType = descriptor.ControllerTypeInfo?.AsType();
if (controllerType == null)
{
throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
nameof(descriptor.ControllerTypeInfo),
nameof(descriptor)),
nameof(descriptor));
}

if (_controllerActivatorCreate != null)
{
return _controllerActivatorCreate;
}

var typeActivator = ActivatorUtilities.CreateFactory(controllerType, Type.EmptyTypes);
return controllerContext => typeActivator(controllerContext.HttpContext.RequestServices, arguments: null);
}

public Action<ControllerContext, object> CreateReleaser(ControllerActionDescriptor descriptor)
{
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

if (_controllerActivatorRelease != null)
{
return _controllerActivatorRelease;
}

if (typeof(IDisposable).GetTypeInfo().IsAssignableFrom(descriptor.ControllerTypeInfo))
{
return _dispose;
}

return null;
}

private static void Dispose(ControllerContext context, object controller)
{
if (controller == null)
{
throw new ArgumentNullException(nameof(controller));
}

((IDisposable)controller).Dispose();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Internal;

namespace Microsoft.AspNetCore.Mvc.Controllers
{
public class ControllerFactoryProvider : IControllerFactoryProvider
{
private readonly IControllerActivatorProvider _activatorProvider;
private readonly Func<ControllerContext, object> _factoryCreateController;
private readonly Action<ControllerContext, object> _factoryReleaseController;
private readonly IControllerPropertyActivator[] _propertyActivators;

public ControllerFactoryProvider(
IControllerActivatorProvider activatorProvider,
IControllerFactory controllerFactory,
IEnumerable<IControllerPropertyActivator> propertyActivators)
{
if (activatorProvider == null)
{
throw new ArgumentNullException(nameof(activatorProvider));
}

if (controllerFactory == null)
{
throw new ArgumentNullException(nameof(controllerFactory));
}

_activatorProvider = activatorProvider;

// Compat: Delegate to the IControllerFactory if it's not the default implementation.
if (controllerFactory.GetType() != typeof(DefaultControllerFactory))
{
_factoryCreateController = controllerFactory.CreateController;
_factoryReleaseController = controllerFactory.ReleaseController;
}

_propertyActivators = propertyActivators.ToArray();
}

public Func<ControllerContext, object> CreateControllerFactory(ControllerActionDescriptor descriptor)
{
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

var controllerType = descriptor.ControllerTypeInfo?.AsType();
if (controllerType == null)
{
throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
nameof(descriptor.ControllerTypeInfo),
nameof(descriptor)),
nameof(descriptor));
}

if (_factoryCreateController != null)
{
return _factoryCreateController;
}

var controllerActivator = _activatorProvider.CreateActivator(descriptor);
var propertyActivators = GetPropertiesToActivate(descriptor);
object CreateController(ControllerContext controllerContext)
{
var controller = controllerActivator(controllerContext);
for (var i = 0; i < propertyActivators.Length; i++)
{
var propertyActivator = propertyActivators[i];
propertyActivator(controllerContext, controller);
}

return controller;
}

return CreateController;
}

public Action<ControllerContext, object> CreateControllerReleaser(ControllerActionDescriptor descriptor)
{
if (descriptor == null)
{
throw new ArgumentNullException(nameof(descriptor));
}

var controllerType = descriptor.ControllerTypeInfo?.AsType();
if (controllerType == null)
{
throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
nameof(descriptor.ControllerTypeInfo),
nameof(descriptor)),
nameof(descriptor));
}

if (_factoryReleaseController != null)
{
return _factoryReleaseController;
}

return _activatorProvider.CreateReleaser(descriptor);
}

private Action<ControllerContext, object>[] GetPropertiesToActivate(ControllerActionDescriptor actionDescriptor)
{
var propertyActivators = new Action<ControllerContext, object>[_propertyActivators.Length];
for (var i = 0; i < _propertyActivators.Length; i++)
{
var activatorProvider = _propertyActivators[i];
propertyActivators[i] = activatorProvider.GetActivatorDelegate(actionDescriptor);
}

return propertyActivators;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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;

namespace Microsoft.AspNetCore.Mvc.Controllers
{
/// <summary>
/// Provides methods to create a MVC controller.
/// </summary>
public interface IControllerActivatorProvider
{
/// <summary>
/// Creates a <see cref="Func{T, TResult}"/> that creates a controller.
/// </summary>
/// <param name="descriptor">The <see cref="ControllerActionDescriptor"/>.</param>
/// <returns>The delegate used to activate the controller.</returns>
Func<ControllerContext, object> CreateActivator(ControllerActionDescriptor descriptor);

/// <summary>
/// Creates an <see cref="Action"/> that releases a controller.
/// </summary>
/// <param name="descriptor">The <see cref="ControllerActionDescriptor"/>.</param>
/// <returns>The delegate used to dispose the activated controller.</returns>
Action<ControllerContext, object> CreateReleaser(ControllerActionDescriptor descriptor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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;

namespace Microsoft.AspNetCore.Mvc.Controllers
{
/// <summary>
/// Provides methods to create and release a controller.
/// </summary>
public interface IControllerFactoryProvider
{
/// <summary>
/// Creates a factory for producing controllers for the specified <paramref name="descriptor"/>.
/// </summary>
/// <param name="descriptor">The <see cref="ControllerActionDescriptor"/>.</param>
/// <returns>The controller factory.</returns>
Func<ControllerContext, object> CreateControllerFactory(ControllerActionDescriptor descriptor);

/// <summary>
/// Releases a controller.
/// </summary>
/// <param name="descriptor">The <see cref="ControllerActionDescriptor"/>.</param>
/// <returns>The delegate used to release the created controller.</returns>
Action<ControllerContext, object> CreateControllerReleaser(ControllerActionDescriptor descriptor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ internal static void AddMvcCoreServices(IServiceCollection services)

// Will be cached by the DefaultControllerFactory
services.TryAddTransient<IControllerActivator, DefaultControllerActivator>();

services.TryAddSingleton<IControllerFactoryProvider, ControllerFactoryProvider>();
services.TryAddSingleton<IControllerActivatorProvider, ControllerActivatorProvider>();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IControllerPropertyActivator, DefaultControllerPropertyActivator>());

Expand Down
Loading

0 comments on commit 37f7e72

Please sign in to comment.