[Fixes #4294] TypeActivate MvcRouteHandler
This commit is contained in:
parent
b96851ec20
commit
3d0f436a06
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue