Support route data tokens with Endpoint Routing (#8360)
This commit is contained in:
parent
5cdc172b17
commit
927e7c8bfc
|
|
@ -174,6 +174,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
endpointInfo.Defaults,
|
||||
++conventionalRouteOrder,
|
||||
endpointInfo,
|
||||
endpointInfo.DataTokens,
|
||||
suppressLinkGeneration: false,
|
||||
suppressPathMatching: false);
|
||||
endpoints.Add(subEndpoint);
|
||||
|
|
@ -214,6 +215,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
endpointInfo.Defaults,
|
||||
++conventionalRouteOrder,
|
||||
endpointInfo,
|
||||
endpointInfo.DataTokens,
|
||||
suppressLinkGeneration: false,
|
||||
suppressPathMatching: false);
|
||||
endpoints.Add(endpoint);
|
||||
|
|
@ -229,6 +231,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
nonInlineDefaults: null,
|
||||
action.AttributeRouteInfo.Order,
|
||||
action.AttributeRouteInfo,
|
||||
dataTokens: null,
|
||||
suppressLinkGeneration: action.AttributeRouteInfo.SuppressLinkGeneration,
|
||||
suppressPathMatching: action.AttributeRouteInfo.SuppressPathMatching);
|
||||
endpoints.Add(endpoint);
|
||||
|
|
@ -378,20 +381,13 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
object nonInlineDefaults,
|
||||
int order,
|
||||
object source,
|
||||
RouteValueDictionary dataTokens,
|
||||
bool suppressLinkGeneration,
|
||||
bool suppressPathMatching)
|
||||
{
|
||||
RequestDelegate requestDelegate = (context) =>
|
||||
{
|
||||
var values = context.Features.Get<IRouteValuesFeature>().RouteValues;
|
||||
var routeData = new RouteData();
|
||||
foreach (var kvp in values)
|
||||
{
|
||||
if (kvp.Value != null)
|
||||
{
|
||||
routeData.Values.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
var routeData = context.GetRouteData();
|
||||
|
||||
var actionContext = new ActionContext(context, routeData, action);
|
||||
|
||||
|
|
@ -407,6 +403,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
routeName,
|
||||
new RouteValueDictionary(action.RouteValues),
|
||||
source,
|
||||
dataTokens,
|
||||
suppressLinkGeneration,
|
||||
suppressPathMatching);
|
||||
|
||||
|
|
@ -425,6 +422,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
string routeName,
|
||||
RouteValueDictionary requiredValues,
|
||||
object source,
|
||||
RouteValueDictionary dataTokens,
|
||||
bool suppressLinkGeneration,
|
||||
bool suppressPathMatching)
|
||||
{
|
||||
|
|
@ -438,6 +436,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
metadata.AddRange(action.EndpointMetadata);
|
||||
}
|
||||
|
||||
if (dataTokens != null)
|
||||
{
|
||||
metadata.Add(new DataTokensMetadata(dataTokens));
|
||||
}
|
||||
|
||||
metadata.Add(new RouteValuesAddressMetadata(routeName, requiredValues));
|
||||
|
||||
// Add filter descriptors to endpoint metadata
|
||||
|
|
@ -506,7 +509,10 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
{
|
||||
foreach (var kvp in requiredValues)
|
||||
{
|
||||
defaults[kvp.Key] = kvp.Value;
|
||||
if (kvp.Value != null)
|
||||
{
|
||||
defaults[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
var featureCollection = new FeatureCollection();
|
||||
featureCollection.Set<IEndpointFeature>(endpointFeature);
|
||||
featureCollection.Set<IRouteValuesFeature>(endpointFeature);
|
||||
featureCollection.Set<IRoutingFeature>(endpointFeature);
|
||||
|
||||
var httpContextMock = new Mock<HttpContext>();
|
||||
httpContextMock.Setup(m => m.Features).Returns(featureCollection);
|
||||
|
|
@ -694,28 +695,6 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
AssertIsSubset(expectedDefaults, matcherEndpoint.RoutePattern.Defaults);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequiredValues_HavingNull_AndNotPresentInDefaultValues_IsAddedToDefaultValues()
|
||||
{
|
||||
// Arrange
|
||||
var requiredValues = new RouteValueDictionary(
|
||||
new { area = (string)null, controller = "Foo", action = "Bar", page = (string)null });
|
||||
var expectedDefaults = requiredValues;
|
||||
var actionDescriptorCollection = GetActionDescriptorCollection(requiredValues: requiredValues);
|
||||
var dataSource = CreateMvcEndpointDataSource(actionDescriptorCollection);
|
||||
dataSource.ConventionalEndpointInfos.Add(
|
||||
CreateEndpointInfo(string.Empty, "{controller=Home}/{action=Index}"));
|
||||
|
||||
// Act
|
||||
var endpoints = dataSource.Endpoints;
|
||||
|
||||
// Assert
|
||||
var endpoint = Assert.Single(endpoints);
|
||||
var matcherEndpoint = Assert.IsType<RouteEndpoint>(endpoint);
|
||||
Assert.Equal("Foo/Bar", matcherEndpoint.RoutePattern.RawText);
|
||||
AssertIsSubset(expectedDefaults, matcherEndpoint.RoutePattern.Defaults);
|
||||
}
|
||||
|
||||
private MvcEndpointDataSource CreateMvcEndpointDataSource(
|
||||
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider = null,
|
||||
MvcEndpointInvokerFactory mvcEndpointInvokerFactory = null)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,30 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
|||
public string[] Routers { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DataTokens_ReturnsDataTokensForRoute()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/DataTokensRoute/DataTokens/Index");
|
||||
|
||||
// Assert
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(body);
|
||||
Assert.Single(result, kvp => kvp.Key == "hasDataTokens" && ((bool)kvp.Value) == true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DataTokens_ReturnsNoDataTokensForRoute()
|
||||
{
|
||||
// Arrange & Act
|
||||
var response = await Client.GetAsync("http://localhost/DataTokens/Index");
|
||||
|
||||
// Assert
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(body);
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public virtual async Task ConventionalRoutedController_ActionIsReachable()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
// 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 Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace RoutingWebSite
|
||||
{
|
||||
public class DataTokensController : Controller
|
||||
{
|
||||
public object Index()
|
||||
{
|
||||
return RouteData.DataTokens;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,12 +24,19 @@ namespace RoutingWebSite
|
|||
{
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
"DataTokensRoute",
|
||||
"DataTokensRoute/{controller}/{action}",
|
||||
defaults: null,
|
||||
constraints: new { controller = "DataTokens" },
|
||||
dataTokens: new { hasDataTokens = true });
|
||||
|
||||
routes.MapAreaRoute(
|
||||
"flightRoute",
|
||||
"adminRoute",
|
||||
"{area:exists}/{controller}/{action}",
|
||||
new { controller = "Home", action = "Index" },
|
||||
new { area = "Travel" });
|
||||
"flightRoute",
|
||||
"adminRoute",
|
||||
"{area:exists}/{controller}/{action}",
|
||||
defaults: new { controller = "Home", action = "Index" },
|
||||
constraints: new { area = "Travel" });
|
||||
|
||||
routes.MapRoute(
|
||||
"ActionAsMethod",
|
||||
|
|
|
|||
|
|
@ -24,12 +24,19 @@ namespace RoutingWebSite
|
|||
{
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute(
|
||||
"DataTokensRoute",
|
||||
"DataTokensRoute/{controller}/{action}",
|
||||
defaults: null,
|
||||
constraints: new { controller = "DataTokens" },
|
||||
dataTokens: new { hasDataTokens = true });
|
||||
|
||||
routes.MapAreaRoute(
|
||||
"flightRoute",
|
||||
"adminRoute",
|
||||
"{area:exists}/{controller}/{action}",
|
||||
new { controller = "Home", action = "Index" },
|
||||
new { area = "Travel" });
|
||||
"flightRoute",
|
||||
"adminRoute",
|
||||
"{area:exists}/{controller}/{action}",
|
||||
defaults: new { controller = "Home", action = "Index" },
|
||||
constraints: new { area = "Travel" });
|
||||
|
||||
routes.MapRoute(
|
||||
"ActionAsMethod",
|
||||
|
|
|
|||
Loading…
Reference in New Issue