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

Commit

Permalink
[Fixes #4294] TypeActivate MvcRouteHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
ajaybhargavb committed May 25, 2016
1 parent b96851e commit 3d0f436
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public static IApplicationBuilder UseMvc(

var routes = new RouteBuilder(app)
{
DefaultHandler = new MvcRouteHandler(),
DefaultHandler = app.ApplicationServices.GetRequiredService<MvcRouteHandler>(),
};

configureRoutes(routes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,11 @@ internal static void AddMvcCoreServices(IServiceCollection services)
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)
Expand Down
54 changes: 26 additions & 28 deletions src/Microsoft.AspNetCore.Mvc.Core/Internal/MvcRouteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,44 @@
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)
Expand All @@ -43,8 +66,6 @@ public Task RouteAsync(RouteContext context)
throw new ArgumentNullException(nameof(context));
}

EnsureServices(context.HttpContext);

var actionDescriptor = _actionSelector.Select(context);
if (actionDescriptor == null)
{
Expand Down Expand Up @@ -107,28 +128,5 @@ private async Task InvokeActionAsync(HttpContext httpContext, ActionDescriptor a
_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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public async Task RouteHandler_Success_LogsCorrectValues()
.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
Expand Down Expand Up @@ -62,11 +62,12 @@ public async Task RouteAsync_FailOnNoAction_LogsCorrectValues()
.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
Expand Down Expand Up @@ -95,8 +96,8 @@ public async Task RouteHandler_RemovesRouteGroupFromRouteValues()
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");
Expand All @@ -117,10 +118,10 @@ public async Task RouteHandler_WritesDiagnostic_ActionSelected()
// 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
Expand All @@ -143,9 +144,9 @@ public async Task RouteHandler_WritesDiagnostic_ActionInvoked()
// 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
Expand All @@ -156,14 +157,15 @@ public async Task RouteHandler_WritesDiagnostic_ActionInvoked()
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>();
Expand All @@ -175,10 +177,20 @@ private RouteContext CreateRouteContext(
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>();
Expand All @@ -192,46 +204,19 @@ private RouteContext CreateRouteContext(
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);
Expand Down

0 comments on commit 3d0f436

Please sign in to comment.