[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)
{
DefaultHandler = new MvcRouteHandler(),
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
};
configureRoutes(routes);

View File

@ -207,6 +207,11 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton(ArrayPool<byte>.Shared);
services.TryAddSingleton(ArrayPool<char>.Shared);
services.TryAddSingleton<ObjectResultExecutor>();
//
// Setup default handler
//
services.TryAddSingleton<MvcRouteHandler>();
}
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.Routing;
using Microsoft.AspNetCore.Routing.Tree;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Mvc.Internal
{
public class MvcRouteHandler : IRouter
{
private bool _servicesRetrieved;
private IActionContextAccessor _actionContextAccessor;
private IActionInvokerFactory _actionInvokerFactory;
private IActionSelector _actionSelector;
private ILogger _logger;
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)
{
if (context == null)
@ -43,8 +66,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
throw new ArgumentNullException(nameof(context));
}
EnsureServices(context.HttpContext);
var actionDescriptor = _actionSelector.Select(context);
if (actionDescriptor == null)
{
@ -107,28 +128,5 @@ namespace Microsoft.AspNetCore.Mvc.Internal
_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)
.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);
// Act
@ -62,11 +62,12 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
.Setup(a => a.Select(It.IsAny<RouteContext>()))
.Returns<ActionDescriptor>(null);
var context = CreateRouteContext(
var context = CreateRouteContext();
var handler = CreateMvcRouteHandler(
actionSelector: mockActionSelector.Object,
loggerFactory: loggerFactory);
var handler = new MvcRouteHandler();
var expectedMessage = "No actions matched the current request";
// Act
@ -95,8 +96,8 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
return invoker.Object;
});
var context = CreateRouteContext(invokerFactory: invokerFactory.Object);
var handler = new MvcRouteHandler();
var context = CreateRouteContext();
var handler = CreateMvcRouteHandler(invokerFactory: invokerFactory.Object);
var originalRouteData = context.RouteData;
originalRouteData.Values.Add(TreeRouter.RouteGroupKey, "/Home/Test");
@ -117,10 +118,10 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
// Arrange
var listener = new TestDiagnosticListener();
var context = CreateRouteContext(diagnosticListener: listener);
var context = CreateRouteContext();
context.RouteData.Values.Add("tag", "value");
var handler = new MvcRouteHandler();
var handler = CreateMvcRouteHandler(diagnosticListener: listener);
await handler.RouteAsync(context);
// Act
@ -143,9 +144,9 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
// Arrange
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);
// Act
@ -156,14 +157,15 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
Assert.NotNull(listener.AfterAction?.HttpContext);
}
private RouteContext CreateRouteContext(
private MvcRouteHandler CreateMvcRouteHandler(
ActionDescriptor actionDescriptor = null,
IActionSelector actionSelector = null,
IActionInvokerFactory invokerFactory = null,
ILoggerFactory loggerFactory = null,
IOptions<MvcOptions> optionsAccessor = null,
object diagnosticListener = null)
{
var actionContextAccessor = new ActionContextAccessor();
if (actionDescriptor == null)
{
var mockAction = new Mock<ActionDescriptor>();
@ -175,10 +177,20 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
var mockActionSelector = new Mock<IActionSelector>();
mockActionSelector.Setup(a => a.Select(It.IsAny<RouteContext>()))
.Returns(actionDescriptor);
actionSelector = mockActionSelector.Object;
}
if (loggerFactory == null)
{
loggerFactory = NullLoggerFactory.Instance;
}
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
if (diagnosticListener != null)
{
diagnosticSource.SubscribeWithAdapter(diagnosticListener);
}
if (invokerFactory == null)
{
var mockInvoker = new Mock<IActionInvoker>();
@ -192,46 +204,19 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
invokerFactory = mockInvokerFactory.Object;
}
if (loggerFactory == null)
{
loggerFactory = NullLoggerFactory.Instance;
}
if (optionsAccessor == null)
{
optionsAccessor = new TestOptionsManager<MvcOptions>();
}
var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
if (diagnosticListener != null)
{
diagnosticSource.SubscribeWithAdapter(diagnosticListener);
}
return new MvcRouteHandler(
invokerFactory,
actionSelector,
diagnosticSource,
loggerFactory,
actionContextAccessor);
}
private RouteContext CreateRouteContext()
{
var routingFeature = new RoutingFeature();
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
.Setup(h => h.Features[typeof(IRoutingFeature)])
.Returns(routingFeature);