From 57cc8aea96cf93724e3b90dec612af717656aeab Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 6 Sep 2018 19:18:14 -0700 Subject: [PATCH] Various improvments to route values link APIs - Add docs - Add support for templates - Remove undesirable constructor parameter - misc cleanup --- samples/RoutingSample.Web/Program.cs | 3 +- ...nkGeneratorRouteValuesAddressExtensions.cs | 76 +++++++++++++++++++ .../RouteValuesBasedEndpointFinder.cs | 18 ++--- .../RouteValueBasedEndpointFinderTest.cs | 22 ++---- 4 files changed, 88 insertions(+), 31 deletions(-) diff --git a/samples/RoutingSample.Web/Program.cs b/samples/RoutingSample.Web/Program.cs index 1fa90c645c..07fe40f30f 100644 --- a/samples/RoutingSample.Web/Program.cs +++ b/samples/RoutingSample.Web/Program.cs @@ -60,8 +60,7 @@ namespace RoutingSample.Web return new WebHostBuilder() .UseKestrel() .UseIISIntegration() - .UseStartup(startupType) - .ConfigureLogging(l => l.AddConsole().SetMinimumLevel(LogLevel.Debug)); + .UseStartup(startupType); } } } diff --git a/src/Microsoft.AspNetCore.Routing/LinkGeneratorRouteValuesAddressExtensions.cs b/src/Microsoft.AspNetCore.Routing/LinkGeneratorRouteValuesAddressExtensions.cs index 0e2f8a663c..3f8014f8e2 100644 --- a/src/Microsoft.AspNetCore.Routing/LinkGeneratorRouteValuesAddressExtensions.cs +++ b/src/Microsoft.AspNetCore.Routing/LinkGeneratorRouteValuesAddressExtensions.cs @@ -11,6 +11,19 @@ namespace Microsoft.AspNetCore.Routing /// public static class LinkGeneratorRouteValuesAddressExtensions { + /// + /// Generates a URI with an absolute path based on the provided values. + /// + /// The . + /// The associated with the current request. + /// The route name. Used to resolve endpoints. Optional. + /// The route values. Used to resolve endpoints and expand parameters in the route template. Optional. + /// An optional URI fragment. Appended to the resulting URI. + /// + /// An optional . Settings on provided object override the settings with matching + /// names from RouteOptions. + /// + /// A URI with an absolute path, or null. public static string GetPathByRouteValues( this LinkGenerator generator, HttpContext httpContext, @@ -28,6 +41,19 @@ namespace Microsoft.AspNetCore.Routing return generator.GetPathByAddress(httpContext, address, address.ExplicitValues, fragment, options); } + /// + /// Generates a URI with an absolute path based on the provided values. + /// + /// The . + /// The route name. Used to resolve endpoints. Optional. + /// The route values. Used to resolve endpoints and expand parameters in the route template. Optional. + /// An optional URI path base. Prepended to the path in the resulting URI. + /// An optional URI fragment. Appended to the resulting URI. + /// + /// An optional . Settings on provided object override the settings with matching + /// names from RouteOptions. + /// + /// A URI with an absolute path, or null. public static string GetPathByRouteValues( this LinkGenerator generator, string routeName, @@ -45,6 +71,19 @@ namespace Microsoft.AspNetCore.Routing return generator.GetPathByAddress(address, address.ExplicitValues, pathBase, fragment, options); } + /// + /// Generates an absolute URI based on the provided values. + /// + /// The . + /// The associated with the current request. + /// The route name. Used to resolve endpoints. Optional. + /// The route values. Used to resolve endpoints and expand parameters in the route template. Optional. + /// An optional URI fragment. Appended to the resulting URI. + /// + /// An optional . Settings on provided object override the settings with matching + /// names from RouteOptions. + /// + /// A URI with an absolute path, or null. public static string GetUriByRouteValues( this LinkGenerator generator, HttpContext httpContext, @@ -62,6 +101,21 @@ namespace Microsoft.AspNetCore.Routing return generator.GetUriByAddress(httpContext, address, address.ExplicitValues, fragment, options); } + /// + /// Generates an absolute URI based on the provided values. + /// + /// The . + /// The route name. Used to resolve endpoints. Optional. + /// The route values. Used to resolve endpoints and expand parameters in the route template. Optional. + /// The URI scheme, applied to the resulting URI. + /// The URI host/authority, applied to the resulting URI. + /// An optional URI path base. Prepended to the path in the resulting URI. + /// An optional URI fragment. Appended to the resulting URI. + /// + /// An optional . Settings on provided object override the settings with matching + /// names from RouteOptions. + /// + /// An absolute URI, or null. public static string GetUriByRouteValues( this LinkGenerator generator, string routeName, @@ -81,7 +135,29 @@ namespace Microsoft.AspNetCore.Routing return generator.GetUriByAddress(address, address.ExplicitValues, scheme, host, pathBase, fragment, options); } + /// + /// Gets a based on the provided and . + /// + /// The . + /// The route name. Used to resolve endpoints. Optional. + /// The route values. Used to resolve endpoints and expand parameters in the route template. Optional. + /// + /// A if one or more endpoints matching the address can be found, otherwise null. + /// + 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(address); + } + private static RouteValuesAddress CreateAddress(HttpContext httpContext, string routeName, object values) { return new RouteValuesAddress() diff --git a/src/Microsoft.AspNetCore.Routing/RouteValuesBasedEndpointFinder.cs b/src/Microsoft.AspNetCore.Routing/RouteValuesBasedEndpointFinder.cs index 3ce63cea56..f7d6b77023 100644 --- a/src/Microsoft.AspNetCore.Routing/RouteValuesBasedEndpointFinder.cs +++ b/src/Microsoft.AspNetCore.Routing/RouteValuesBasedEndpointFinder.cs @@ -6,33 +6,27 @@ using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing.Internal; -using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Tree; -using Microsoft.Extensions.ObjectPool; namespace Microsoft.AspNetCore.Routing { internal class RouteValuesBasedEndpointFinder : IEndpointFinder { - private readonly CompositeEndpointDataSource _endpointDataSource; - private readonly ObjectPool _objectPool; + private readonly CompositeEndpointDataSource _dataSource; private LinkGenerationDecisionTree _allMatchesLinkGenerationTree; private IDictionary> _namedMatchResults; - public RouteValuesBasedEndpointFinder( - CompositeEndpointDataSource endpointDataSource, - ObjectPool objectPool) + public RouteValuesBasedEndpointFinder(CompositeEndpointDataSource dataSource) { - _endpointDataSource = endpointDataSource; - _objectPool = objectPool; + _dataSource = dataSource; // Build initial matches BuildOutboundMatches(); // Register for changes in endpoints Extensions.Primitives.ChangeToken.OnChange( - _endpointDataSource.GetChangeToken, + _dataSource.GetChangeToken, 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 // is produced every time Extensions.Primitives.ChangeToken.OnChange( - _endpointDataSource.GetChangeToken, + _dataSource.GetChangeToken, HandleChange); } @@ -104,7 +98,7 @@ namespace Microsoft.AspNetCore.Routing var namedOutboundMatchResults = new Dictionary>( StringComparer.OrdinalIgnoreCase); - var endpoints = _endpointDataSource.Endpoints.OfType(); + var endpoints = _dataSource.Endpoints.OfType(); foreach (var endpoint in endpoints) { // Do not consider an endpoint for link generation if the following marker metadata is on it diff --git a/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs b/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs index c3c1f644e8..70c66b052e 100644 --- a/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs +++ b/test/Microsoft.AspNetCore.Routing.Tests/RouteValueBasedEndpointFinderTest.cs @@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.TestObjects; using Microsoft.AspNetCore.Routing.Tree; -using Microsoft.Extensions.ObjectPool; using Xunit; namespace Microsoft.AspNetCore.Routing @@ -83,13 +82,9 @@ namespace Microsoft.AspNetCore.Routing // Arrange 1 var endpoint1 = CreateEndpoint("/a"); var dynamicDataSource = new DynamicEndpointDataSource(new[] { endpoint1 }); - var objectPoolProvider = new DefaultObjectPoolProvider(); - var objectPool = objectPoolProvider.Create(new UriBuilderContextPooledObjectPolicy()); // Act 1 - var finder = new CustomRouteValuesBasedEndpointFinder( - new CompositeEndpointDataSource(new[] { dynamicDataSource }), - objectPool); + var finder = new CustomRouteValuesBasedEndpointFinder(new CompositeEndpointDataSource(new[] { dynamicDataSource })); // Assert 1 Assert.NotNull(finder.AllMatches); @@ -218,14 +213,9 @@ namespace Microsoft.AspNetCore.Routing return CreateEndpointFinder(new DefaultEndpointDataSource(endpoints)); } - private CustomRouteValuesBasedEndpointFinder CreateEndpointFinder(params EndpointDataSource[] endpointDataSources) + private CustomRouteValuesBasedEndpointFinder CreateEndpointFinder(params EndpointDataSource[] dataSources) { - var objectPoolProvider = new DefaultObjectPoolProvider(); - var objectPool = objectPoolProvider.Create(new UriBuilderContextPooledObjectPolicy()); - - return new CustomRouteValuesBasedEndpointFinder( - new CompositeEndpointDataSource(endpointDataSources), - objectPool); + return new CustomRouteValuesBasedEndpointFinder(new CompositeEndpointDataSource(dataSources)); } private RouteEndpoint CreateEndpoint( @@ -256,10 +246,8 @@ namespace Microsoft.AspNetCore.Routing private class CustomRouteValuesBasedEndpointFinder : RouteValuesBasedEndpointFinder { - public CustomRouteValuesBasedEndpointFinder( - CompositeEndpointDataSource endpointDataSource, - ObjectPool objectPool) - : base(endpointDataSource, objectPool) + public CustomRouteValuesBasedEndpointFinder(CompositeEndpointDataSource dataSource) + : base(dataSource) { }