Various improvments to route values link APIs
- Add docs - Add support for templates - Remove undesirable constructor parameter - misc cleanup
This commit is contained in:
parent
c683844817
commit
57cc8aea96
|
|
@ -60,8 +60,7 @@ namespace RoutingSample.Web
|
||||||
return new WebHostBuilder()
|
return new WebHostBuilder()
|
||||||
.UseKestrel()
|
.UseKestrel()
|
||||||
.UseIISIntegration()
|
.UseIISIntegration()
|
||||||
.UseStartup(startupType)
|
.UseStartup(startupType);
|
||||||
.ConfigureLogging(l => l.AddConsole().SetMinimumLevel(LogLevel.Debug));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,19 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class LinkGeneratorRouteValuesAddressExtensions
|
public static class LinkGeneratorRouteValuesAddressExtensions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a URI with an absolute path based on the provided values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="generator">The <see cref="LinkGenerator"/>.</param>
|
||||||
|
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||||
|
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
|
||||||
|
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
|
||||||
|
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
|
||||||
|
/// <param name="options">
|
||||||
|
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||||
|
/// names from <c>RouteOptions</c>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A URI with an absolute path, or <c>null</c>.</returns>
|
||||||
public static string GetPathByRouteValues(
|
public static string GetPathByRouteValues(
|
||||||
this LinkGenerator generator,
|
this LinkGenerator generator,
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
|
|
@ -28,6 +41,19 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return generator.GetPathByAddress<RouteValuesAddress>(httpContext, address, address.ExplicitValues, fragment, options);
|
return generator.GetPathByAddress<RouteValuesAddress>(httpContext, address, address.ExplicitValues, fragment, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a URI with an absolute path based on the provided values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="generator">The <see cref="LinkGenerator"/>.</param>
|
||||||
|
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
|
||||||
|
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
|
||||||
|
/// <param name="pathBase">An optional URI path base. Prepended to the path in the resulting URI.</param>
|
||||||
|
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
|
||||||
|
/// <param name="options">
|
||||||
|
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||||
|
/// names from <c>RouteOptions</c>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A URI with an absolute path, or <c>null</c>.</returns>
|
||||||
public static string GetPathByRouteValues(
|
public static string GetPathByRouteValues(
|
||||||
this LinkGenerator generator,
|
this LinkGenerator generator,
|
||||||
string routeName,
|
string routeName,
|
||||||
|
|
@ -45,6 +71,19 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return generator.GetPathByAddress<RouteValuesAddress>(address, address.ExplicitValues, pathBase, fragment, options);
|
return generator.GetPathByAddress<RouteValuesAddress>(address, address.ExplicitValues, pathBase, fragment, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates an absolute URI based on the provided values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="generator">The <see cref="LinkGenerator"/>.</param>
|
||||||
|
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||||
|
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
|
||||||
|
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
|
||||||
|
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
|
||||||
|
/// <param name="options">
|
||||||
|
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||||
|
/// names from <c>RouteOptions</c>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>A URI with an absolute path, or <c>null</c>.</returns>
|
||||||
public static string GetUriByRouteValues(
|
public static string GetUriByRouteValues(
|
||||||
this LinkGenerator generator,
|
this LinkGenerator generator,
|
||||||
HttpContext httpContext,
|
HttpContext httpContext,
|
||||||
|
|
@ -62,6 +101,21 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return generator.GetUriByAddress<RouteValuesAddress>(httpContext, address, address.ExplicitValues, fragment, options);
|
return generator.GetUriByAddress<RouteValuesAddress>(httpContext, address, address.ExplicitValues, fragment, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates an absolute URI based on the provided values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="generator">The <see cref="LinkGenerator"/>.</param>
|
||||||
|
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
|
||||||
|
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
|
||||||
|
/// <param name="scheme">The URI scheme, applied to the resulting URI.</param>
|
||||||
|
/// <param name="host">The URI host/authority, applied to the resulting URI.</param>
|
||||||
|
/// <param name="pathBase">An optional URI path base. Prepended to the path in the resulting URI.</param>
|
||||||
|
/// <param name="fragment">An optional URI fragment. Appended to the resulting URI.</param>
|
||||||
|
/// <param name="options">
|
||||||
|
/// An optional <see cref="LinkOptions"/>. Settings on provided object override the settings with matching
|
||||||
|
/// names from <c>RouteOptions</c>.
|
||||||
|
/// </param>
|
||||||
|
/// <returns>An absolute URI, or <c>null</c>.</returns>
|
||||||
public static string GetUriByRouteValues(
|
public static string GetUriByRouteValues(
|
||||||
this LinkGenerator generator,
|
this LinkGenerator generator,
|
||||||
string routeName,
|
string routeName,
|
||||||
|
|
@ -81,6 +135,28 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return generator.GetUriByAddress<RouteValuesAddress>(address, address.ExplicitValues, scheme, host, pathBase, fragment, options);
|
return generator.GetUriByAddress<RouteValuesAddress>(address, address.ExplicitValues, scheme, host, pathBase, fragment, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a <see cref="LinkGenerationTemplate"/> based on the provided <paramref name="routeName"/> and <paramref name="values"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="generator">The <see cref="LinkGenerator"/>.</param>
|
||||||
|
/// <param name="routeName">The route name. Used to resolve endpoints. Optional.</param>
|
||||||
|
/// <param name="values">The route values. Used to resolve endpoints and expand parameters in the route template. Optional.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="LinkGenerationTemplate"/> if one or more endpoints matching the address can be found, otherwise <c>null</c>.
|
||||||
|
/// </returns>
|
||||||
|
public static LinkGenerationTemplate GetTemplateByRouteValues(
|
||||||
|
this LinkGenerator generator,
|
||||||
|
string routeName,
|
||||||
|
object values)
|
||||||
|
{
|
||||||
|
if (generator == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(generator));
|
||||||
|
}
|
||||||
|
|
||||||
|
var address = CreateAddress(httpContext: null, routeName, values);
|
||||||
|
return generator.GetTemplateByAddress<RouteValuesAddress>(address);
|
||||||
|
}
|
||||||
|
|
||||||
private static RouteValuesAddress CreateAddress(HttpContext httpContext, string routeName, object values)
|
private static RouteValuesAddress CreateAddress(HttpContext httpContext, string routeName, object values)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,33 +6,27 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Matching;
|
|
||||||
using Microsoft.AspNetCore.Routing.Template;
|
using Microsoft.AspNetCore.Routing.Template;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
internal class RouteValuesBasedEndpointFinder : IEndpointFinder<RouteValuesAddress>
|
internal class RouteValuesBasedEndpointFinder : IEndpointFinder<RouteValuesAddress>
|
||||||
{
|
{
|
||||||
private readonly CompositeEndpointDataSource _endpointDataSource;
|
private readonly CompositeEndpointDataSource _dataSource;
|
||||||
private readonly ObjectPool<UriBuildingContext> _objectPool;
|
|
||||||
private LinkGenerationDecisionTree _allMatchesLinkGenerationTree;
|
private LinkGenerationDecisionTree _allMatchesLinkGenerationTree;
|
||||||
private IDictionary<string, List<OutboundMatchResult>> _namedMatchResults;
|
private IDictionary<string, List<OutboundMatchResult>> _namedMatchResults;
|
||||||
|
|
||||||
public RouteValuesBasedEndpointFinder(
|
public RouteValuesBasedEndpointFinder(CompositeEndpointDataSource dataSource)
|
||||||
CompositeEndpointDataSource endpointDataSource,
|
|
||||||
ObjectPool<UriBuildingContext> objectPool)
|
|
||||||
{
|
{
|
||||||
_endpointDataSource = endpointDataSource;
|
_dataSource = dataSource;
|
||||||
_objectPool = objectPool;
|
|
||||||
|
|
||||||
// Build initial matches
|
// Build initial matches
|
||||||
BuildOutboundMatches();
|
BuildOutboundMatches();
|
||||||
|
|
||||||
// Register for changes in endpoints
|
// Register for changes in endpoints
|
||||||
Extensions.Primitives.ChangeToken.OnChange(
|
Extensions.Primitives.ChangeToken.OnChange(
|
||||||
_endpointDataSource.GetChangeToken,
|
_dataSource.GetChangeToken,
|
||||||
HandleChange);
|
HandleChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,7 +62,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// re-register the callback as the change token is one time use only and a new change token
|
// re-register the callback as the change token is one time use only and a new change token
|
||||||
// is produced every time
|
// is produced every time
|
||||||
Extensions.Primitives.ChangeToken.OnChange(
|
Extensions.Primitives.ChangeToken.OnChange(
|
||||||
_endpointDataSource.GetChangeToken,
|
_dataSource.GetChangeToken,
|
||||||
HandleChange);
|
HandleChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var namedOutboundMatchResults = new Dictionary<string, List<OutboundMatchResult>>(
|
var namedOutboundMatchResults = new Dictionary<string, List<OutboundMatchResult>>(
|
||||||
StringComparer.OrdinalIgnoreCase);
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var endpoints = _endpointDataSource.Endpoints.OfType<RouteEndpoint>();
|
var endpoints = _dataSource.Endpoints.OfType<RouteEndpoint>();
|
||||||
foreach (var endpoint in endpoints)
|
foreach (var endpoint in endpoints)
|
||||||
{
|
{
|
||||||
// Do not consider an endpoint for link generation if the following marker metadata is on it
|
// Do not consider an endpoint for link generation if the following marker metadata is on it
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Routing.Internal;
|
||||||
using Microsoft.AspNetCore.Routing.Patterns;
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.AspNetCore.Routing.TestObjects;
|
using Microsoft.AspNetCore.Routing.TestObjects;
|
||||||
using Microsoft.AspNetCore.Routing.Tree;
|
using Microsoft.AspNetCore.Routing.Tree;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
@ -83,13 +82,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Arrange 1
|
// Arrange 1
|
||||||
var endpoint1 = CreateEndpoint("/a");
|
var endpoint1 = CreateEndpoint("/a");
|
||||||
var dynamicDataSource = new DynamicEndpointDataSource(new[] { endpoint1 });
|
var dynamicDataSource = new DynamicEndpointDataSource(new[] { endpoint1 });
|
||||||
var objectPoolProvider = new DefaultObjectPoolProvider();
|
|
||||||
var objectPool = objectPoolProvider.Create(new UriBuilderContextPooledObjectPolicy());
|
|
||||||
|
|
||||||
// Act 1
|
// Act 1
|
||||||
var finder = new CustomRouteValuesBasedEndpointFinder(
|
var finder = new CustomRouteValuesBasedEndpointFinder(new CompositeEndpointDataSource(new[] { dynamicDataSource }));
|
||||||
new CompositeEndpointDataSource(new[] { dynamicDataSource }),
|
|
||||||
objectPool);
|
|
||||||
|
|
||||||
// Assert 1
|
// Assert 1
|
||||||
Assert.NotNull(finder.AllMatches);
|
Assert.NotNull(finder.AllMatches);
|
||||||
|
|
@ -218,14 +213,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return CreateEndpointFinder(new DefaultEndpointDataSource(endpoints));
|
return CreateEndpointFinder(new DefaultEndpointDataSource(endpoints));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomRouteValuesBasedEndpointFinder CreateEndpointFinder(params EndpointDataSource[] endpointDataSources)
|
private CustomRouteValuesBasedEndpointFinder CreateEndpointFinder(params EndpointDataSource[] dataSources)
|
||||||
{
|
{
|
||||||
var objectPoolProvider = new DefaultObjectPoolProvider();
|
return new CustomRouteValuesBasedEndpointFinder(new CompositeEndpointDataSource(dataSources));
|
||||||
var objectPool = objectPoolProvider.Create(new UriBuilderContextPooledObjectPolicy());
|
|
||||||
|
|
||||||
return new CustomRouteValuesBasedEndpointFinder(
|
|
||||||
new CompositeEndpointDataSource(endpointDataSources),
|
|
||||||
objectPool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RouteEndpoint CreateEndpoint(
|
private RouteEndpoint CreateEndpoint(
|
||||||
|
|
@ -256,10 +246,8 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
private class CustomRouteValuesBasedEndpointFinder : RouteValuesBasedEndpointFinder
|
private class CustomRouteValuesBasedEndpointFinder : RouteValuesBasedEndpointFinder
|
||||||
{
|
{
|
||||||
public CustomRouteValuesBasedEndpointFinder(
|
public CustomRouteValuesBasedEndpointFinder(CompositeEndpointDataSource dataSource)
|
||||||
CompositeEndpointDataSource endpointDataSource,
|
: base(dataSource)
|
||||||
ObjectPool<UriBuildingContext> objectPool)
|
|
||||||
: base(endpointDataSource, objectPool)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue