Refactor MVC endpoint integration for templates (#8695)

This commit is contained in:
James Newton-King 2018-11-15 17:04:26 +13:00 committed by GitHub
parent 9ff5a441f5
commit 6270ea48a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 80 deletions

View File

@ -33,12 +33,11 @@ namespace MvcSandbox
pattern: "/endpoints",
displayName: "Home");
builder.MapMvcRoute(
builder.MapControllerRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
builder.MapMvcControllers();
builder.MapRazorPages();
builder.MapApplication();
builder.MapHealthChecks("/healthz");
});

View File

@ -43,7 +43,6 @@ namespace Microsoft.AspNetCore.Builder
public string Name { get; }
public string Pattern { get; }
public Type ControllerType { get; set; }
// Non-inline defaults
public RouteValueDictionary Defaults { get; }

View File

@ -1,8 +1,8 @@
// 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.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Routing;
@ -12,14 +12,21 @@ namespace Microsoft.AspNetCore.Builder
{
public static class MvcEndpointRouteBuilderExtensions
{
public static IEndpointConventionBuilder MapMvcControllers(
public static IEndpointConventionBuilder MapApplication(
this IEndpointRouteBuilder routeBuilder)
{
return MapMvcControllers<ControllerBase>(routeBuilder);
return MapActionDescriptors(routeBuilder, null);
}
public static IEndpointConventionBuilder MapMvcControllers<TController>(
this IEndpointRouteBuilder routeBuilder) where TController : ControllerBase
public static IEndpointConventionBuilder MapAssembly<TContainingType>(
this IEndpointRouteBuilder routeBuilder)
{
return MapActionDescriptors(routeBuilder, typeof(TContainingType));
}
private static IEndpointConventionBuilder MapActionDescriptors(
this IEndpointRouteBuilder routeBuilder,
Type containingType)
{
var mvcEndpointDataSource = routeBuilder.DataSources.OfType<MvcEndpointDataSource>().FirstOrDefault();
@ -31,92 +38,64 @@ namespace Microsoft.AspNetCore.Builder
var conventionBuilder = new DefaultEndpointConventionBuilder();
var assemblyFilter = containingType?.Assembly;
mvcEndpointDataSource.AttributeRoutingConventionResolvers.Add(actionDescriptor =>
{
if (actionDescriptor is ControllerActionDescriptor controllerActionDescriptor &&
typeof(TController).IsAssignableFrom(controllerActionDescriptor.ControllerTypeInfo))
// Filter a descriptor by the assembly
// Note that this will only filter actions on controllers
// Does not support filtering Razor pages embedded in assemblies
if (assemblyFilter != null)
{
return conventionBuilder;
if (actionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
{
if (controllerActionDescriptor.ControllerTypeInfo.Assembly != assemblyFilter)
{
return null;
}
}
}
return null;
return conventionBuilder;
});
return conventionBuilder;
}
public static IEndpointConventionBuilder MapMvcRoute(
public static IEndpointConventionBuilder MapControllerRoute(
this IEndpointRouteBuilder routeBuilder,
string name,
string template)
{
return MapMvcRoute<ControllerBase>(routeBuilder, name, template, defaults: null);
return MapControllerRoute(routeBuilder, name, template, defaults: null);
}
public static IEndpointConventionBuilder MapMvcRoute(
public static IEndpointConventionBuilder MapControllerRoute(
this IEndpointRouteBuilder routeBuilder,
string name,
string template,
object defaults)
{
return MapMvcRoute<ControllerBase>(routeBuilder, name, template, defaults, constraints: null);
return MapControllerRoute(routeBuilder, name, template, defaults, constraints: null);
}
public static IEndpointConventionBuilder MapMvcRoute(
public static IEndpointConventionBuilder MapControllerRoute(
this IEndpointRouteBuilder routeBuilder,
string name,
string template,
object defaults,
object constraints)
{
return MapMvcRoute<ControllerBase>(routeBuilder, name, template, defaults, constraints, dataTokens: null);
return MapControllerRoute(routeBuilder, name, template, defaults, constraints, dataTokens: null);
}
public static IEndpointConventionBuilder MapMvcRoute(
public static IEndpointConventionBuilder MapControllerRoute(
this IEndpointRouteBuilder routeBuilder,
string name,
string template,
object defaults,
object constraints,
object dataTokens)
{
return MapMvcRoute<ControllerBase>(routeBuilder, name, template, defaults, constraints, dataTokens);
}
public static IEndpointConventionBuilder MapMvcRoute<TController>(
this IEndpointRouteBuilder routeBuilder,
string name,
string template) where TController : ControllerBase
{
return MapMvcRoute<TController>(routeBuilder, name, template, defaults: null);
}
public static IEndpointConventionBuilder MapMvcRoute<TController>(
this IEndpointRouteBuilder routeBuilder,
string name,
string template,
object defaults) where TController : ControllerBase
{
return MapMvcRoute<TController>(routeBuilder, name, template, defaults, constraints: null);
}
public static IEndpointConventionBuilder MapMvcRoute<TController>(
this IEndpointRouteBuilder routeBuilder,
string name,
string template,
object defaults,
object constraints) where TController : ControllerBase
{
return MapMvcRoute<TController>(routeBuilder, name, template, defaults, constraints, dataTokens: null);
}
public static IEndpointConventionBuilder MapMvcRoute<TController>(
this IEndpointRouteBuilder routeBuilder,
string name,
string template,
object defaults,
object constraints,
object dataTokens) where TController : ControllerBase
{
var mvcEndpointDataSource = routeBuilder.DataSources.OfType<MvcEndpointDataSource>().FirstOrDefault();
@ -134,8 +113,6 @@ namespace Microsoft.AspNetCore.Builder
new RouteValueDictionary(dataTokens),
routeBuilder.ServiceProvider.GetRequiredService<ParameterPolicyFactory>());
endpointInfo.ControllerType = typeof(TController);
mvcEndpointDataSource.ConventionalEndpointInfos.Add(endpointInfo);
return endpointInfo;

View File

@ -139,16 +139,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
// - Home/Login
foreach (var endpointInfo in ConventionalEndpointInfos)
{
if (endpointInfo.ControllerType != null &&
endpointInfo.ControllerType != typeof(ControllerBase))
{
if (!ValidateControllerConstraint(action, endpointInfo))
{
// Action descriptor does not belong to a controller of the specified type
continue;
}
}
// An 'endpointInfo' is applicable if:
// 1. it has a parameter (or default value) for 'required' non-null route value
// 2. it does not have a parameter (or default value) for 'required' null route value
@ -244,16 +234,6 @@ namespace Microsoft.AspNetCore.Mvc.Routing
return null;
}
private static bool ValidateControllerConstraint(ActionDescriptor action, MvcEndpointInfo endpointInfo)
{
if (action is ControllerActionDescriptor controllerActionDescriptor)
{
return endpointInfo.ControllerType.IsAssignableFrom(controllerActionDescriptor.ControllerTypeInfo);
}
return false;
}
// CreateEndpoints processes the route pattern, replacing area/controller/action parameters with endpoint values
// Because of default values it is possible for a route pattern to resolve to multiple endpoints
private int CreateEndpoints(