[Fixes #4294] TypeActivate MvcRouteHandler

This commit is contained in:
Ajay Bhargav Baaskaran 2016-05-24 18:30:43 -07:00
parent b96851ec20
commit 3d0f436a06
4 changed files with 66 additions and 78 deletions

View File

@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Builder
var routes = new RouteBuilder(app) var routes = new RouteBuilder(app)
{ {
DefaultHandler = new MvcRouteHandler(), DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
}; };
configureRoutes(routes); configureRoutes(routes);

View File

@ -207,6 +207,11 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton(ArrayPool<byte>.Shared); services.TryAddSingleton(ArrayPool<byte>.Shared);
services.TryAddSingleton(ArrayPool<char>.Shared); services.TryAddSingleton(ArrayPool<char>.Shared);
services.TryAddSingleton<ObjectResultExecutor>(); services.TryAddSingleton<ObjectResultExecutor>();
//
// Setup default handler
//
services.TryAddSingleton<MvcRouteHandler>();
} }
private static void ConfigureDefaultServices(IServiceCollection services) private static void ConfigureDefaultServices(IServiceCollection services)

View File

@ -10,21 +10,44 @@ using Microsoft.AspNetCore.Mvc.Core;
using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Tree; using Microsoft.AspNetCore.Routing.Tree;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.Internal namespace Microsoft.AspNetCore.Mvc.Internal
{ {
public class MvcRouteHandler : IRouter public class MvcRouteHandler : IRouter
{ {
private bool _servicesRetrieved;
private IActionContextAccessor _actionContextAccessor; private IActionContextAccessor _actionContextAccessor;
private IActionInvokerFactory _actionInvokerFactory; private IActionInvokerFactory _actionInvokerFactory;
private IActionSelector _actionSelector; private IActionSelector _actionSelector;
private ILogger _logger; private ILogger _logger;
private DiagnosticSource _diagnosticSource; private DiagnosticSource _diagnosticSource;
public MvcRouteHandler(
IActionInvokerFactory actionInvokerFactory,
IActionSelector actionSelector,
DiagnosticSource diagnosticSource,
ILoggerFactory loggerFactory)
: this(actionInvokerFactory, actionSelector, diagnosticSource, loggerFactory, actionContextAccessor: null)
{
}
public MvcRouteHandler(
IActionInvokerFactory actionInvokerFactory,
IActionSelector actionSelector,
DiagnosticSource diagnosticSource,
ILoggerFactory loggerFactory,
IActionContextAccessor actionContextAccessor)
{
// The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext
// if possible.
_actionContextAccessor = actionContextAccessor;
_actionInvokerFactory = actionInvokerFactory;
_actionSelector = actionSelector;
_diagnosticSource = diagnosticSource;
_logger = loggerFactory.CreateLogger<MvcRouteHandler>();
}
public VirtualPathData GetVirtualPath(VirtualPathContext context) public VirtualPathData GetVirtualPath(VirtualPathContext context)
{ {
if (context == null) if (context == null)
@ -43,8 +66,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
throw new ArgumentNullException(nameof(context)); throw new ArgumentNullException(nameof(context));
} }
EnsureServices(context.HttpContext);
var actionDescriptor = _actionSelector.Select(context); var actionDescriptor = _actionSelector.Select(context);
if (actionDescriptor == null) if (actionDescriptor == null)
{ {
@ -107,28 +128,5 @@ namespace Microsoft.AspNetCore.Mvc.Internal
_diagnosticSource.AfterAction(actionDescriptor, httpContext, routeData); _diagnosticSource.AfterAction(actionDescriptor, httpContext, routeData);
} }
} }
private void EnsureServices(HttpContext context)
{
if (_servicesRetrieved)
{
return;
}
var services = context.RequestServices;
// The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext
// if possible.
_actionContextAccessor = services.GetService<IActionContextAccessor>();
_actionInvokerFactory = services.GetRequiredService<IActionInvokerFactory>();
_actionSelector = services.GetRequiredService<IActionSelector>();
_diagnosticSource = services.GetRequiredService<DiagnosticSource>();
var factory = services.GetRequiredService<ILoggerFactory>();
_logger = factory.CreateLogger<MvcRouteHandler>();
_servicesRetrieved = true;
}
} }
} }

View File

@ -32,9 +32,9 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
.SetupGet(ad => ad.DisplayName) .SetupGet(ad => ad.DisplayName)
.Returns(displayName); .Returns(displayName);
var context = CreateRouteContext(actionDescriptor: actionDescriptor.Object, loggerFactory: loggerFactory); var context = CreateRouteContext();
var handler = new MvcRouteHandler(); var handler = CreateMvcRouteHandler(actionDescriptor: actionDescriptor.Object, loggerFactory: loggerFactory);
await handler.RouteAsync(context); await handler.RouteAsync(context);
// Act // Act
@ -62,11 +62,12 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
.Setup(a => a.Select(It.IsAny<RouteContext>())) .Setup(a => a.Select(It.IsAny<RouteContext>()))
.Returns<ActionDescriptor>(null); .Returns<ActionDescriptor>(null);
var context = CreateRouteContext( var context = CreateRouteContext();
var handler = CreateMvcRouteHandler(
actionSelector: mockActionSelector.Object, actionSelector: mockActionSelector.Object,
loggerFactory: loggerFactory); loggerFactory: loggerFactory);
var handler = new MvcRouteHandler();
var expectedMessage = "No actions matched the current request"; var expectedMessage = "No actions matched the current request";
// Act // Act
@ -95,8 +96,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
return invoker.Object; return invoker.Object;
}); });
var context = CreateRouteContext(invokerFactory: invokerFactory.Object); var context = CreateRouteContext();
var handler = new MvcRouteHandler(); var handler = CreateMvcRouteHandler(invokerFactory: invokerFactory.Object);
var originalRouteData = context.RouteData; var originalRouteData = context.RouteData;
originalRouteData.Values.Add(TreeRouter.RouteGroupKey, "/Home/Test"); originalRouteData.Values.Add(TreeRouter.RouteGroupKey, "/Home/Test");
@ -117,10 +118,10 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
// Arrange // Arrange
var listener = new TestDiagnosticListener(); var listener = new TestDiagnosticListener();
var context = CreateRouteContext(diagnosticListener: listener); var context = CreateRouteContext();
context.RouteData.Values.Add("tag", "value"); context.RouteData.Values.Add("tag", "value");
var handler = new MvcRouteHandler(); var handler = CreateMvcRouteHandler(diagnosticListener: listener);
await handler.RouteAsync(context); await handler.RouteAsync(context);
// Act // Act
@ -143,9 +144,9 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
// Arrange // Arrange
var listener = new TestDiagnosticListener(); var listener = new TestDiagnosticListener();
var context = CreateRouteContext(diagnosticListener: listener); var context = CreateRouteContext();
var handler = new MvcRouteHandler(); var handler = CreateMvcRouteHandler(diagnosticListener: listener);
await handler.RouteAsync(context); await handler.RouteAsync(context);
// Act // Act
@ -156,14 +157,15 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
Assert.NotNull(listener.AfterAction?.HttpContext); Assert.NotNull(listener.AfterAction?.HttpContext);
} }
private RouteContext CreateRouteContext( private MvcRouteHandler CreateMvcRouteHandler(
ActionDescriptor actionDescriptor = null, ActionDescriptor actionDescriptor = null,
IActionSelector actionSelector = null, IActionSelector actionSelector = null,
IActionInvokerFactory invokerFactory = null, IActionInvokerFactory invokerFactory = null,
ILoggerFactory loggerFactory = null, ILoggerFactory loggerFactory = null,
IOptions<MvcOptions> optionsAccessor = null,
object diagnosticListener = null) object diagnosticListener = null)
{ {
var actionContextAccessor = new ActionContextAccessor();
if (actionDescriptor == null) if (actionDescriptor == null)
{ {
var mockAction = new Mock<ActionDescriptor>(); var mockAction = new Mock<ActionDescriptor>();
@ -175,10 +177,20 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
var mockActionSelector = new Mock<IActionSelector>(); var mockActionSelector = new Mock<IActionSelector>();
mockActionSelector.Setup(a => a.Select(It.IsAny<RouteContext>())) mockActionSelector.Setup(a => a.Select(It.IsAny<RouteContext>()))
.Returns(actionDescriptor); .Returns(actionDescriptor);
actionSelector = mockActionSelector.Object; actionSelector = mockActionSelector.Object;
} }
if (loggerFactory == null)
{
loggerFactory = NullLoggerFactory.Instance;
}
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
if (diagnosticListener != null)
{
diagnosticSource.SubscribeWithAdapter(diagnosticListener);
}
if (invokerFactory == null) if (invokerFactory == null)
{ {
var mockInvoker = new Mock<IActionInvoker>(); var mockInvoker = new Mock<IActionInvoker>();
@ -192,46 +204,19 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
invokerFactory = mockInvokerFactory.Object; invokerFactory = mockInvokerFactory.Object;
} }
if (loggerFactory == null) return new MvcRouteHandler(
{ invokerFactory,
loggerFactory = NullLoggerFactory.Instance; actionSelector,
} diagnosticSource,
loggerFactory,
if (optionsAccessor == null) actionContextAccessor);
{ }
optionsAccessor = new TestOptionsManager<MvcOptions>();
}
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
if (diagnosticListener != null)
{
diagnosticSource.SubscribeWithAdapter(diagnosticListener);
}
private RouteContext CreateRouteContext()
{
var routingFeature = new RoutingFeature(); var routingFeature = new RoutingFeature();
var httpContext = new Mock<HttpContext>(); var httpContext = new Mock<HttpContext>();
httpContext
.Setup(h => h.RequestServices.GetService(typeof(IActionContextAccessor)))
.Returns(new ActionContextAccessor());
httpContext
.Setup(h => h.RequestServices.GetService(typeof(IActionSelector)))
.Returns(actionSelector);
httpContext
.Setup(h => h.RequestServices.GetService(typeof(IActionInvokerFactory)))
.Returns(invokerFactory);
httpContext
.Setup(h => h.RequestServices.GetService(typeof(ILoggerFactory)))
.Returns(loggerFactory);
httpContext
.Setup(h => h.RequestServices.GetService(typeof(MvcMarkerService)))
.Returns(new MvcMarkerService());
httpContext
.Setup(h => h.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
httpContext
.Setup(h => h.RequestServices.GetService(typeof(DiagnosticSource)))
.Returns(diagnosticSource);
httpContext httpContext
.Setup(h => h.Features[typeof(IRoutingFeature)]) .Setup(h => h.Features[typeof(IRoutingFeature)])
.Returns(routingFeature); .Returns(routingFeature);