Add documentation for Routing surface area (#26513)
* Add documentation for Routing surface area * Apply suggestions from code review Co-authored-by: James Newton-King <james@newtonking.com> * Fix up some doc strings Co-authored-by: James Newton-King <james@newtonking.com>
This commit is contained in:
parent
63baa06482
commit
cd94cd63b7
|
|
@ -4,7 +4,7 @@
|
||||||
namespace Microsoft.AspNetCore.Http
|
namespace Microsoft.AspNetCore.Http
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A collection of contants for HTTP status codes.
|
/// A collection of constants for HTTP status codes.
|
||||||
///
|
///
|
||||||
/// Status Codes listed at http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
/// Status Codes listed at http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Http;
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a contract for a handler of a route.
|
/// Defines a contract for a handler of a route.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRouteHandler
|
public interface IRouteHandler
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Interface for implementing a router.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRouter
|
public interface IRouter
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -205,4 +205,4 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Builder
|
namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constains extensions for configuring routing on an <see cref="IApplicationBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
public static class EndpointRoutingApplicationBuilderExtensions
|
public static class EndpointRoutingApplicationBuilderExtensions
|
||||||
{
|
{
|
||||||
private const string EndpointRouteBuilder = "__EndpointRouteBuilder";
|
private const string EndpointRouteBuilder = "__EndpointRouteBuilder";
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
_dataSources = dataSources;
|
_dataSources = dataSources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates a <see cref="CompositeEndpointDataSource"/> object from <paramref name="endpointDataSources"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="endpointDataSources">An collection of <see cref="EndpointDataSource" /> objects.</param>
|
||||||
|
/// <returns>A <see cref="CompositeEndpointDataSource"/> </returns>
|
||||||
public CompositeEndpointDataSource(IEnumerable<EndpointDataSource> endpointDataSources) : this()
|
public CompositeEndpointDataSource(IEnumerable<EndpointDataSource> endpointDataSources) : this()
|
||||||
{
|
{
|
||||||
_dataSources = new List<EndpointDataSource>();
|
_dataSources = new List<EndpointDataSource>();
|
||||||
|
|
@ -62,6 +67,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the collection of <see cref="EndpointDataSource"/> instances associated with the object.
|
||||||
|
/// </summary>
|
||||||
public IEnumerable<EndpointDataSource> DataSources => _dataSources;
|
public IEnumerable<EndpointDataSource> DataSources => _dataSources;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -123,12 +131,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
// Refresh the endpoints from datasource so that callbacks can get the latest endpoints
|
// Refresh the endpoints from datasource so that callbacks can get the latest endpoints
|
||||||
_endpoints = _dataSources.SelectMany(d => d.Endpoints).ToArray();
|
_endpoints = _dataSources.SelectMany(d => d.Endpoints).ToArray();
|
||||||
|
|
||||||
// Prevent consumers from re-registering callback to inflight events as that can
|
// Prevent consumers from re-registering callback to inflight events as that can
|
||||||
// cause a stackoverflow
|
// cause a stackoverflow
|
||||||
// Example:
|
// Example:
|
||||||
// 1. B registers A
|
// 1. B registers A
|
||||||
// 2. A fires event causing B's callback to get called
|
// 2. A fires event causing B's callback to get called
|
||||||
// 3. B executes some code in its callback, but needs to re-register callback
|
// 3. B executes some code in its callback, but needs to re-register callback
|
||||||
// in the same callback
|
// in the same callback
|
||||||
var oldTokenSource = _cts;
|
var oldTokenSource = _cts;
|
||||||
var oldToken = _consumerChangeToken;
|
var oldToken = _consumerChangeToken;
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,14 @@ using Microsoft.AspNetCore.Http;
|
||||||
namespace Microsoft.AspNetCore.Routing.Constraints
|
namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a constraint on an optional parameter. If the parameter is present, then it is constrained by InnerConstraint.
|
/// Defines a constraint on an optional parameter. If the parameter is present, then it is constrained by InnerConstraint.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OptionalRouteConstraint : IRouteConstraint
|
public class OptionalRouteConstraint : IRouteConstraint
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="OptionalRouteConstraint"/> instance given the <paramref name="innerConstraint"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="innerConstraint"></param>
|
||||||
public OptionalRouteConstraint(IRouteConstraint innerConstraint)
|
public OptionalRouteConstraint(IRouteConstraint innerConstraint)
|
||||||
{
|
{
|
||||||
if (innerConstraint == null)
|
if (innerConstraint == null)
|
||||||
|
|
@ -21,8 +25,12 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
InnerConstraint = innerConstraint;
|
InnerConstraint = innerConstraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="IRouteConstraint"/> associated with the optional parameter.
|
||||||
|
/// </summary>
|
||||||
public IRouteConstraint InnerConstraint { get; }
|
public IRouteConstraint InnerConstraint { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool Match(
|
public bool Match(
|
||||||
HttpContext? httpContext,
|
HttpContext? httpContext,
|
||||||
IRouter? route,
|
IRouter? route,
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,17 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Constraints
|
namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constrains a route parameter to match a regular expression.
|
||||||
|
/// </summary>
|
||||||
public class RegexRouteConstraint : IRouteConstraint
|
public class RegexRouteConstraint : IRouteConstraint
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10);
|
private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for a <see cref="RegexRouteConstraint"/> given a <paramref name="regex"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regex">A <see cref="Regex"/> instance to use as a constraint.</param>
|
||||||
public RegexRouteConstraint(Regex regex)
|
public RegexRouteConstraint(Regex regex)
|
||||||
{
|
{
|
||||||
if (regex == null)
|
if (regex == null)
|
||||||
|
|
@ -22,6 +29,10 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
Constraint = regex;
|
Constraint = regex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for a <see cref="RegexRouteConstraint"/> given a <paramref name="regexPattern"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="regexPattern">A string containing the regex pattern.</param>
|
||||||
public RegexRouteConstraint(string regexPattern)
|
public RegexRouteConstraint(string regexPattern)
|
||||||
{
|
{
|
||||||
if (regexPattern == null)
|
if (regexPattern == null)
|
||||||
|
|
@ -35,8 +46,12 @@ namespace Microsoft.AspNetCore.Routing.Constraints
|
||||||
RegexMatchTimeout);
|
RegexMatchTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the regular expression used in the route constraint.
|
||||||
|
/// </summary>
|
||||||
public Regex Constraint { get; private set; }
|
public Regex Constraint { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool Match(
|
public bool Match(
|
||||||
HttpContext? httpContext,
|
HttpContext? httpContext,
|
||||||
IRouter? route,
|
IRouter? route,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class DataTokensMetadata : IDataTokensMetadata
|
public sealed class DataTokensMetadata : IDataTokensMetadata
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for a new <see cref="DataTokensMetadata"/> given <paramref name="dataTokens"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataTokens">The data tokens.</param>
|
||||||
public DataTokensMetadata(IReadOnlyDictionary<string, object> dataTokens)
|
public DataTokensMetadata(IReadOnlyDictionary<string, object> dataTokens)
|
||||||
{
|
{
|
||||||
if (dataTokens == null)
|
if (dataTokens == null)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,14 @@
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An interface for an <see cref="IRouter"/> with a name.
|
||||||
|
/// </summary>
|
||||||
public interface INamedRouter : IRouter
|
public interface INamedRouter : IRouter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the router. Can be null.
|
||||||
|
/// </summary>
|
||||||
string? Name { get; }
|
string? Name { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,15 @@
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for a router that supports appending new routes.
|
||||||
|
/// </summary>
|
||||||
public interface IRouteCollection : IRouter
|
public interface IRouteCollection : IRouter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the collection of routes defined in <paramref name="router"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="router">A <see cref="IRouter"/> instance.</param>
|
||||||
void Add(IRouter router);
|
void Add(IRouter router);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,16 @@ using Microsoft.AspNetCore.Routing.Template;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains methods for parsing processing constraints from a route definition.
|
||||||
|
/// </summary>
|
||||||
public static class InlineRouteParameterParser
|
public static class InlineRouteParameterParser
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a string representing the provided <paramref name="routeParameter"/> into a <see cref="TemplatePart"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="routeParameter">A string representation of the route parameter.</param>
|
||||||
|
/// <returns>A <see cref="TemplatePart"/> instance.</returns>
|
||||||
public static TemplatePart ParseRouteParameter(string routeParameter)
|
public static TemplatePart ParseRouteParameter(string routeParameter)
|
||||||
{
|
{
|
||||||
if (routeParameter == null)
|
if (routeParameter == null)
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,20 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for a <see cref="DfaGraphWriter"/> given <paramref name="services"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
|
||||||
public DfaGraphWriter(IServiceProvider services)
|
public DfaGraphWriter(IServiceProvider services)
|
||||||
{
|
{
|
||||||
_services = services;
|
_services = services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Displays a graph representation of <paramref name="dataSource"/> in DOT.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataSource">The <see cref="EndpointDataSource"/> to extract routes from.</param>
|
||||||
|
/// <param name="writer">The <see cref="TextWriter"/> to which the content is written.</param>
|
||||||
public void Write(EndpointDataSource dataSource, TextWriter writer)
|
public void Write(EndpointDataSource dataSource, TextWriter writer)
|
||||||
{
|
{
|
||||||
var builder = _services.GetRequiredService<DfaMatcherBuilder>();
|
var builder = _services.GetRequiredService<DfaMatcherBuilder>();
|
||||||
|
|
@ -46,7 +55,7 @@ namespace Microsoft.AspNetCore.Routing.Internal
|
||||||
|
|
||||||
// Assign each node a sequential index.
|
// Assign each node a sequential index.
|
||||||
var visited = new Dictionary<DfaNode, int>();
|
var visited = new Dictionary<DfaNode, int>();
|
||||||
|
|
||||||
var tree = builder.BuildDfaTree(includeLabel: true);
|
var tree = builder.BuildDfaTree(includeLabel: true);
|
||||||
|
|
||||||
writer.WriteLine("digraph DFA {");
|
writer.WriteLine("digraph DFA {");
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,9 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
/// </typeparam>
|
/// </typeparam>
|
||||||
public abstract class EndpointMetadataComparer<TMetadata> : IComparer<Endpoint> where TMetadata : class
|
public abstract class EndpointMetadataComparer<TMetadata> : IComparer<Endpoint> where TMetadata : class
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A default instance of the <see cref="EndpointMetadataComparer"/>.
|
||||||
|
/// </summary>
|
||||||
public static readonly EndpointMetadataComparer<TMetadata> Default = new DefaultComparer<TMetadata>();
|
public static readonly EndpointMetadataComparer<TMetadata> Default = new DefaultComparer<TMetadata>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
private const string WildcardPrefix = "*.";
|
private const string WildcardPrefix = "*.";
|
||||||
|
|
||||||
// Run after HTTP methods, but before 'default'.
|
// Run after HTTP methods, but before 'default'.
|
||||||
|
/// <inheritdoc />
|
||||||
public override int Order { get; } = -100;
|
public override int Order { get; } = -100;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IComparer<Endpoint> Comparer { get; } = new HostMetadataEndpointComparer();
|
public IComparer<Endpoint> Comparer { get; } = new HostMetadataEndpointComparer();
|
||||||
|
|
||||||
bool INodeBuilderPolicy.AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
bool INodeBuilderPolicy.AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints)
|
||||||
|
|
@ -70,6 +72,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
|
public Task ApplyAsync(HttpContext httpContext, CandidateSet candidates)
|
||||||
{
|
{
|
||||||
if (httpContext == null)
|
if (httpContext == null)
|
||||||
|
|
@ -189,6 +192,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
throw new InvalidOperationException($"Could not parse host: {host}");
|
throw new InvalidOperationException($"Could not parse host: {host}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IReadOnlyList<PolicyNodeEdge> GetEdges(IReadOnlyList<Endpoint> endpoints)
|
public IReadOnlyList<PolicyNodeEdge> GetEdges(IReadOnlyList<Endpoint> endpoints)
|
||||||
{
|
{
|
||||||
if (endpoints == null)
|
if (endpoints == null)
|
||||||
|
|
@ -273,6 +277,7 @@ namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJumpTableEdge> edges)
|
public PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJumpTableEdge> edges)
|
||||||
{
|
{
|
||||||
if (edges == null)
|
if (edges == null)
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,31 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implements an interface for a matcher policy with support for generating graph representations of the endpoints.
|
||||||
|
/// </summary>
|
||||||
public interface INodeBuilderPolicy
|
public interface INodeBuilderPolicy
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates if the policy matches any of the endpoints provided in <paramref name="endpoints"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="endpoints">A list of <see cref="Endpoint"/>.</param>
|
||||||
|
/// <returns><see langword="true"/> if the policy applies to any of the provided <paramref name="endpoints"/>.</returns>
|
||||||
bool AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints);
|
bool AppliesToEndpoints(IReadOnlyList<Endpoint> endpoints);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates a graph that representations the relationship between endpoints and hosts.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="endpoints">A list of <see cref="Endpoint"/>.</param>
|
||||||
|
/// <returns>A graph representing the relationship between endpoints and hosts.</returns>
|
||||||
IReadOnlyList<PolicyNodeEdge> GetEdges(IReadOnlyList<Endpoint> endpoints);
|
IReadOnlyList<PolicyNodeEdge> GetEdges(IReadOnlyList<Endpoint> endpoints);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a jump table given the a set of <paramref name="edges"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exitDestination">The default destination for lookups.</param>
|
||||||
|
/// <param name="edges">A list of <see cref="PolicyJumpTableEdge"/>.</param>
|
||||||
|
/// <returns>A <see cref="PolicyJumpTable"/> instance.</returns>
|
||||||
PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJumpTableEdge> edges);
|
PolicyJumpTable BuildJumpTable(int exitDestination, IReadOnlyList<PolicyJumpTableEdge> edges);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,15 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supports retrieving endpoints that fulfill a certain matcher policy.
|
||||||
|
/// </summary>
|
||||||
public abstract class PolicyJumpTable
|
public abstract class PolicyJumpTable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the destination for a given <paramref name="httpContext"/> in the current jump table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||||
public abstract int GetDestination(HttpContext httpContext);
|
public abstract int GetDestination(HttpContext httpContext);
|
||||||
|
|
||||||
internal virtual string DebuggerToString()
|
internal virtual string DebuggerToString()
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,31 @@
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an entry in a <see cref="PolicyJumpTable"/>.
|
||||||
|
/// </summary>
|
||||||
public readonly struct PolicyJumpTableEdge
|
public readonly struct PolicyJumpTableEdge
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="PolicyJumpTableEdge"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Represents the match heuristic of the policy.</param>
|
||||||
|
/// <param name="destination"></param>
|
||||||
public PolicyJumpTableEdge(object state, int destination)
|
public PolicyJumpTableEdge(object state, int destination)
|
||||||
{
|
{
|
||||||
State = state ?? throw new System.ArgumentNullException(nameof(state));
|
State = state ?? throw new System.ArgumentNullException(nameof(state));
|
||||||
Destination = destination;
|
Destination = destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the object used to represent the match heuristic. Can be a host, HTTP method, etc.
|
||||||
|
/// depending on the matcher policy.
|
||||||
|
/// </summary>
|
||||||
public object State { get; }
|
public object State { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the destination of the current entry.
|
||||||
|
/// </summary>
|
||||||
public int Destination { get; }
|
public int Destination { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,31 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Matching
|
namespace Microsoft.AspNetCore.Routing.Matching
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an edge in a matcher policy graph.
|
||||||
|
/// </summary>
|
||||||
public readonly struct PolicyNodeEdge
|
public readonly struct PolicyNodeEdge
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="PolicyNodeEdge"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state">Represents the match heuristic of the policy.</param>
|
||||||
|
/// <param name="endpoints">Represents the endpoints that match the policy</param>
|
||||||
public PolicyNodeEdge(object state, IReadOnlyList<Endpoint> endpoints)
|
public PolicyNodeEdge(object state, IReadOnlyList<Endpoint> endpoints)
|
||||||
{
|
{
|
||||||
State = state ?? throw new System.ArgumentNullException(nameof(state));
|
State = state ?? throw new System.ArgumentNullException(nameof(state));
|
||||||
Endpoints = endpoints ?? throw new System.ArgumentNullException(nameof(endpoints));
|
Endpoints = endpoints ?? throw new System.ArgumentNullException(nameof(endpoints));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the endpoints that match the policy defined by <see cref="State"/>.
|
||||||
|
/// </summary>
|
||||||
public IReadOnlyList<Endpoint> Endpoints { get; }
|
public IReadOnlyList<Endpoint> Endpoints { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the object used to represent the match heuristic. Can be a host, HTTP method, etc.
|
||||||
|
/// depending on the matcher policy.
|
||||||
|
/// </summary>
|
||||||
public object State { get; }
|
public object State { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Microsoft.AspNetCore.Routing.Route
|
||||||
Microsoft.AspNetCore.Routing.RouteCollection</Description>
|
Microsoft.AspNetCore.Routing.RouteCollection</Description>
|
||||||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
<IsAspNetCoreApp>true</IsAspNetCoreApp>
|
<IsAspNetCoreApp>true</IsAspNetCoreApp>
|
||||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
<NoWarn>$(NoWarn.Replace('1591', ''))</NoWarn>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PackageTags>aspnetcore;routing</PackageTags>
|
<PackageTags>aspnetcore;routing</PackageTags>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for adding new handlers to a <see cref="IRouteBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
public static class RequestDelegateRouteBuilderExtensions
|
public static class RequestDelegateRouteBuilderExtensions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,19 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an instance of a route.
|
||||||
|
/// </summary>
|
||||||
public class Route : RouteBase
|
public class Route : RouteBase
|
||||||
{
|
{
|
||||||
private readonly IRouter _target;
|
private readonly IRouter _target;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="Route"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">An <see cref="IRouter"/> instance associated with the component.</param>
|
||||||
|
/// <param name="routeTemplate">A string representation of the route template.</param>
|
||||||
|
/// <param name="inlineConstraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
|
||||||
public Route(
|
public Route(
|
||||||
IRouter target,
|
IRouter target,
|
||||||
string routeTemplate,
|
string routeTemplate,
|
||||||
|
|
@ -25,6 +34,15 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="Route"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">An <see cref="IRouter"/> instance associated with the component.</param>
|
||||||
|
/// <param name="routeTemplate">A string representation of the route template.</param>
|
||||||
|
/// <param name="defaults">The default values for parameters in the route.</param>
|
||||||
|
/// <param name="constraints">The constraints for the route.</param>
|
||||||
|
/// <param name="dataTokens">The data tokens for the route.</param>
|
||||||
|
/// <param name="inlineConstraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
|
||||||
public Route(
|
public Route(
|
||||||
IRouter target,
|
IRouter target,
|
||||||
string routeTemplate,
|
string routeTemplate,
|
||||||
|
|
@ -36,6 +54,16 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="Route"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">An <see cref="IRouter"/> instance associated with the component.</param>
|
||||||
|
/// <param name="routeName">The name of the route.</param>
|
||||||
|
/// <param name="routeTemplate">A string representation of the route template.</param>
|
||||||
|
/// <param name="defaults">The default values for parameters in the route.</param>
|
||||||
|
/// <param name="constraints">The constraints for the route.</param>
|
||||||
|
/// <param name="dataTokens">The data tokens for the route.</param>
|
||||||
|
/// <param name="inlineConstraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
|
||||||
public Route(
|
public Route(
|
||||||
IRouter target,
|
IRouter target,
|
||||||
string? routeName,
|
string? routeName,
|
||||||
|
|
@ -45,11 +73,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
RouteValueDictionary? dataTokens,
|
RouteValueDictionary? dataTokens,
|
||||||
IInlineConstraintResolver inlineConstraintResolver)
|
IInlineConstraintResolver inlineConstraintResolver)
|
||||||
: base(
|
: base(
|
||||||
routeTemplate,
|
routeTemplate,
|
||||||
routeName,
|
routeName,
|
||||||
inlineConstraintResolver,
|
inlineConstraintResolver,
|
||||||
defaults,
|
defaults,
|
||||||
constraints,
|
constraints,
|
||||||
dataTokens)
|
dataTokens)
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (target == null)
|
||||||
|
|
@ -60,14 +88,19 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
_target = target;
|
_target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string representation of the route template.
|
||||||
|
/// </summary>
|
||||||
public string? RouteTemplate => ParsedTemplate.TemplateText;
|
public string? RouteTemplate => ParsedTemplate.TemplateText;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override Task OnRouteMatched(RouteContext context)
|
protected override Task OnRouteMatched(RouteContext context)
|
||||||
{
|
{
|
||||||
context.RouteData.Routers.Add(_target);
|
context.RouteData.Routers.Add(_target);
|
||||||
return _target.RouteAsync(context);
|
return _target.RouteAsync(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
protected override VirtualPathData? OnVirtualPathGenerated(VirtualPathContext context)
|
protected override VirtualPathData? OnVirtualPathGenerated(VirtualPathContext context)
|
||||||
{
|
{
|
||||||
return _target.GetVirtualPath(context);
|
return _target.GetVirtualPath(context);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class implementation of an <see cref="IRouter"/>.
|
||||||
|
/// </summary>
|
||||||
public abstract class RouteBase : IRouter, INamedRouter
|
public abstract class RouteBase : IRouter, INamedRouter
|
||||||
{
|
{
|
||||||
private readonly object _loggersLock = new object();
|
private readonly object _loggersLock = new object();
|
||||||
|
|
@ -23,6 +26,15 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
private ILogger? _logger;
|
private ILogger? _logger;
|
||||||
private ILogger? _constraintLogger;
|
private ILogger? _constraintLogger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="RouteBase"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="template">The route template.</param>
|
||||||
|
/// <param name="name">The name of the route.</param>
|
||||||
|
/// <param name="constraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
|
||||||
|
/// <param name="defaults">The default values for parameters in the route.</param>
|
||||||
|
/// <param name="constraints">The constraints for the route.</param>
|
||||||
|
/// <param name="dataTokens">The data tokens for the route.</param>
|
||||||
public RouteBase(
|
public RouteBase(
|
||||||
string? template,
|
string? template,
|
||||||
string? name,
|
string? name,
|
||||||
|
|
@ -56,20 +68,45 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the set of constraints associated with each route.
|
||||||
|
/// </summary>
|
||||||
public virtual IDictionary<string, IRouteConstraint> Constraints { get; protected set; }
|
public virtual IDictionary<string, IRouteConstraint> Constraints { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the resolver used for resolving inline constraints.
|
||||||
|
/// </summary>
|
||||||
protected virtual IInlineConstraintResolver ConstraintResolver { get; set; }
|
protected virtual IInlineConstraintResolver ConstraintResolver { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data tokens associated with the route.
|
||||||
|
/// </summary>
|
||||||
public virtual RouteValueDictionary DataTokens { get; protected set; }
|
public virtual RouteValueDictionary DataTokens { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default values for each route parameter.
|
||||||
|
/// </summary>
|
||||||
public virtual RouteValueDictionary Defaults { get; protected set; }
|
public virtual RouteValueDictionary Defaults { get; protected set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public virtual string? Name { get; protected set; }
|
public virtual string? Name { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="RouteTemplate"/> associated with the route.
|
||||||
|
/// </summary>
|
||||||
public virtual RouteTemplate ParsedTemplate { get; protected set; }
|
public virtual RouteTemplate ParsedTemplate { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes asynchronously whenever routing occurs.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">A <see cref="RouteContext"/> instance.</param>
|
||||||
protected abstract Task OnRouteMatched(RouteContext context);
|
protected abstract Task OnRouteMatched(RouteContext context);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Executes whenever a virtual path is dervied from a <paramref name="context"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">A <see cref="VirtualPathContext"/> instance.</param>
|
||||||
|
/// <returns>A <see cref="VirtualPathData"/> instance.</returns>
|
||||||
protected abstract VirtualPathData? OnVirtualPathGenerated(VirtualPathContext context);
|
protected abstract VirtualPathData? OnVirtualPathGenerated(VirtualPathContext context);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -168,6 +205,12 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return pathData;
|
return pathData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts constatins from a given <see cref="RouteTemplate"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inlineConstraintResolver">An <see cref="IInlineConstraintResolver"/> used for resolving inline constraints.</param>
|
||||||
|
/// <param name="parsedTemplate">A <see cref="RouteTemplate"/> instance.</param>
|
||||||
|
/// <param name="constraints">A collection of constraints on the route template.</param>
|
||||||
protected static IDictionary<string, IRouteConstraint> GetConstraints(
|
protected static IDictionary<string, IRouteConstraint> GetConstraints(
|
||||||
IInlineConstraintResolver inlineConstraintResolver,
|
IInlineConstraintResolver inlineConstraintResolver,
|
||||||
RouteTemplate parsedTemplate,
|
RouteTemplate parsedTemplate,
|
||||||
|
|
@ -199,6 +242,11 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
return constraintBuilder.Build();
|
return constraintBuilder.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default values for parameters in a templates.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parsedTemplate">A <see cref="RouteTemplate"/> instance.</param>
|
||||||
|
/// <param name="defaults">A collection of defaults for each parameter.</param>
|
||||||
protected static RouteValueDictionary GetDefaults(
|
protected static RouteValueDictionary GetDefaults(
|
||||||
RouteTemplate parsedTemplate,
|
RouteTemplate parsedTemplate,
|
||||||
RouteValueDictionary? defaults)
|
RouteValueDictionary? defaults)
|
||||||
|
|
@ -296,6 +344,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return ParsedTemplate.TemplateText!;
|
return ParsedTemplate.TemplateText!;
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,26 @@ using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides support for specifying routes in an application.
|
||||||
|
/// </summary>
|
||||||
public class RouteBuilder : IRouteBuilder
|
public class RouteBuilder : IRouteBuilder
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="RouteBuilder"/> instance given an <paramref name="applicationBuilder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="applicationBuilder">An <see cref="IApplicationBuilder"/> instance.</param>
|
||||||
public RouteBuilder(IApplicationBuilder applicationBuilder)
|
public RouteBuilder(IApplicationBuilder applicationBuilder)
|
||||||
: this(applicationBuilder, defaultHandler: null)
|
: this(applicationBuilder, defaultHandler: null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="RouteBuilder"/> instance given an <paramref name="applicationBuilder"/>
|
||||||
|
/// and <paramref name="defaultHandler"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="applicationBuilder">An <see cref="IApplicationBuilder"/> instance.</param>
|
||||||
|
/// <param name="defaultHandler">The default <see cref="IRouter"/> used if a new route is added without a handler.</param>
|
||||||
public RouteBuilder(IApplicationBuilder applicationBuilder, IRouter? defaultHandler)
|
public RouteBuilder(IApplicationBuilder applicationBuilder, IRouter? defaultHandler)
|
||||||
{
|
{
|
||||||
if (applicationBuilder == null)
|
if (applicationBuilder == null)
|
||||||
|
|
@ -39,14 +52,19 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Routes = new List<IRouter>();
|
Routes = new List<IRouter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IApplicationBuilder ApplicationBuilder { get; }
|
public IApplicationBuilder ApplicationBuilder { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IRouter? DefaultHandler { get; set; }
|
public IRouter? DefaultHandler { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IServiceProvider ServiceProvider { get; }
|
public IServiceProvider ServiceProvider { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IList<IRouter> Routes { get; }
|
public IList<IRouter> Routes { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IRouter Build()
|
public IRouter Build()
|
||||||
{
|
{
|
||||||
var routeCollection = new RouteCollection();
|
var routeCollection = new RouteCollection();
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@ using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supports managing a collection fo multiple routes.
|
||||||
|
/// </summary>
|
||||||
public class RouteCollection : IRouteCollection
|
public class RouteCollection : IRouteCollection
|
||||||
{
|
{
|
||||||
private readonly static char[] UrlQueryDelimiters = new char[] { '?', '#' };
|
private readonly static char[] UrlQueryDelimiters = new char[] { '?', '#' };
|
||||||
|
|
@ -24,16 +27,24 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
|
|
||||||
private RouteOptions? _options;
|
private RouteOptions? _options;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the route at a given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The route at the given index.</value>
|
||||||
public IRouter this[int index]
|
public IRouter this[int index]
|
||||||
{
|
{
|
||||||
get { return _routes[index]; }
|
get { return _routes[index]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total number of routes registered in the collection.
|
||||||
|
/// </summary>
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
get { return _routes.Count; }
|
get { return _routes.Count; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void Add(IRouter router)
|
public void Add(IRouter router)
|
||||||
{
|
{
|
||||||
if (router == null)
|
if (router == null)
|
||||||
|
|
@ -57,6 +68,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
_routes.Add(router);
|
_routes.Add(router);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public async virtual Task RouteAsync(RouteContext context)
|
public async virtual Task RouteAsync(RouteContext context)
|
||||||
{
|
{
|
||||||
// Perf: We want to avoid allocating a new RouteData for each route we need to process.
|
// Perf: We want to avoid allocating a new RouteData for each route we need to process.
|
||||||
|
|
@ -88,6 +100,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public virtual VirtualPathData? GetVirtualPath(VirtualPathContext context)
|
public virtual VirtualPathData? GetVirtualPath(VirtualPathContext context)
|
||||||
{
|
{
|
||||||
EnsureOptions(context.HttpContext);
|
EnsureOptions(context.HttpContext);
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,24 @@ using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Use to evaluate if all route parameter values match their constraints.
|
||||||
|
/// </summary>
|
||||||
public static class RouteConstraintMatcher
|
public static class RouteConstraintMatcher
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if <paramref name="routeValues"/> match the provided <paramref name="constraints"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="constraints">The constraints for the route.</param>
|
||||||
|
/// <param name="routeValues">The route parameter values extracted from the matched route.</param>
|
||||||
|
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||||
|
/// <param name="route">The router that this constraint belongs to.</param>
|
||||||
|
/// <param name="routeDirection">
|
||||||
|
/// Indicates whether the constraint check is performed
|
||||||
|
/// when the incoming request is handled or when a URL is generated.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="logger">The <see cref="ILogger{TCategoryName}"/>.</param>
|
||||||
|
/// <returns><see langword="true"/> if the all route values match their constraints.</returns>
|
||||||
public static bool Match(
|
public static bool Match(
|
||||||
IDictionary<string, IRouteConstraint> constraints,
|
IDictionary<string, IRouteConstraint> constraints,
|
||||||
RouteValueDictionary routeValues,
|
RouteValueDictionary routeValues,
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,27 @@ using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supports building a new <see cref="RouteEndpoint"/>.
|
||||||
|
/// </summary>
|
||||||
public sealed class RouteEndpointBuilder : EndpointBuilder
|
public sealed class RouteEndpointBuilder : EndpointBuilder
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="RoutePattern"/> associated with this endpoint.
|
||||||
|
/// </summary>
|
||||||
public RoutePattern RoutePattern { get; set; }
|
public RoutePattern RoutePattern { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the order assigned to the endpoint.
|
||||||
|
/// </summary>
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="RouteEndpointBuilder"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestDelegate">The delegate used to process requests for the endpoint.</param>
|
||||||
|
/// <param name="routePattern">The <see cref="RoutePattern"/> to use in URL matching.</param>
|
||||||
|
/// <param name="order">The order assigned to the endpoint.</param>
|
||||||
public RouteEndpointBuilder(
|
public RouteEndpointBuilder(
|
||||||
RequestDelegate requestDelegate,
|
RequestDelegate requestDelegate,
|
||||||
RoutePattern routePattern,
|
RoutePattern routePattern,
|
||||||
|
|
@ -24,6 +39,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
Order = order;
|
Order = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public override Endpoint Build()
|
public override Endpoint Build()
|
||||||
{
|
{
|
||||||
if (RequestDelegate is null)
|
if (RequestDelegate is null)
|
||||||
|
|
|
||||||
|
|
@ -8,26 +8,36 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supports implementing a handler that executes for a given route.
|
||||||
|
/// </summary>
|
||||||
public class RouteHandler : IRouteHandler, IRouter
|
public class RouteHandler : IRouteHandler, IRouter
|
||||||
{
|
{
|
||||||
private readonly RequestDelegate _requestDelegate;
|
private readonly RequestDelegate _requestDelegate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="RouteHandler"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="requestDelegate">The delegate used to process requests.</param>
|
||||||
public RouteHandler(RequestDelegate requestDelegate)
|
public RouteHandler(RequestDelegate requestDelegate)
|
||||||
{
|
{
|
||||||
_requestDelegate = requestDelegate;
|
_requestDelegate = requestDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public RequestDelegate GetRequestHandler(HttpContext httpContext, RouteData routeData)
|
public RequestDelegate GetRequestHandler(HttpContext httpContext, RouteData routeData)
|
||||||
{
|
{
|
||||||
return _requestDelegate;
|
return _requestDelegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public VirtualPathData? GetVirtualPath(VirtualPathContext context)
|
public VirtualPathData? GetVirtualPath(VirtualPathContext context)
|
||||||
{
|
{
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public Task RouteAsync(RouteContext context)
|
public Task RouteAsync(RouteContext context)
|
||||||
{
|
{
|
||||||
context.Handler = _requestDelegate;
|
context.Handler = _requestDelegate;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ using Microsoft.AspNetCore.Routing.Constraints;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the configurable options on a route.
|
||||||
|
/// </summary>
|
||||||
public class RouteOptions
|
public class RouteOptions
|
||||||
{
|
{
|
||||||
private IDictionary<string, Type> _constraintTypeMap = GetDefaultConstraintMap();
|
private IDictionary<string, Type> _constraintTypeMap = GetDefaultConstraintMap();
|
||||||
|
|
@ -64,6 +67,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public bool SuppressCheckForUnhandledSecurityMetadata { get; set; }
|
public bool SuppressCheckForUnhandledSecurityMetadata { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a collection of constraints on the current route.
|
||||||
|
/// </summary>
|
||||||
public IDictionary<string, Type> ConstraintMap
|
public IDictionary<string, Type> ConstraintMap
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,9 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class RouteValueEqualityComparer : IEqualityComparer<object?>
|
public class RouteValueEqualityComparer : IEqualityComparer<object?>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A default instance of the <see cref="RouteValueEqualityComparer"/>.
|
||||||
|
/// </summary>
|
||||||
public static readonly RouteValueEqualityComparer Default = new RouteValueEqualityComparer();
|
public static readonly RouteValueEqualityComparer Default = new RouteValueEqualityComparer();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,21 @@ using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Builder
|
namespace Microsoft.AspNetCore.Builder
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Middleware responsible for routing.
|
||||||
|
/// </summary>
|
||||||
public class RouterMiddleware
|
public class RouterMiddleware
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly RequestDelegate _next;
|
private readonly RequestDelegate _next;
|
||||||
private readonly IRouter _router;
|
private readonly IRouter _router;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="RouterMiddleware"/> instance with a given <paramref name="router"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="next">The delegate representing the remaining middleware in the request pipeline.</param>
|
||||||
|
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/>.</param>
|
||||||
|
/// <param name="router">The <see cref="IRouter"/> to use for routing requests.</param>
|
||||||
public RouterMiddleware(
|
public RouterMiddleware(
|
||||||
RequestDelegate next,
|
RequestDelegate next,
|
||||||
ILoggerFactory loggerFactory,
|
ILoggerFactory loggerFactory,
|
||||||
|
|
@ -26,6 +35,11 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
_logger = loggerFactory.CreateLogger<RouterMiddleware>();
|
_logger = loggerFactory.CreateLogger<RouterMiddleware>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates the handler associated with the <see cref="RouteContext"/>
|
||||||
|
/// derived from <paramref name="httpContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpContext">A <see cref="HttpContext"/> instance.</param>
|
||||||
public async Task Invoke(HttpContext httpContext)
|
public async Task Invoke(HttpContext httpContext)
|
||||||
{
|
{
|
||||||
var context = new RouteContext(httpContext);
|
var context = new RouteContext(httpContext);
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,12 @@
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing
|
namespace Microsoft.AspNetCore.Routing
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A feature for routing functionality.
|
||||||
|
/// </summary>
|
||||||
public class RoutingFeature : IRoutingFeature
|
public class RoutingFeature : IRoutingFeature
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public RouteData? RouteData { get; set; }
|
public RouteData? RouteData { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
Constraint = constraint;
|
Constraint = constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="InlineConstraint"/> instance given a <see cref="RoutePatternParameterPolicyReference"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="RoutePatternParameterPolicyReference"/> instance.</param>
|
||||||
public InlineConstraint(RoutePatternParameterPolicyReference other)
|
public InlineConstraint(RoutePatternParameterPolicyReference other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,17 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class RoutePrecedence
|
public static class RoutePrecedence
|
||||||
{
|
{
|
||||||
// Compute the precedence for matching a provided url
|
/// <summary>
|
||||||
// e.g.: /api/template == 1.1
|
/// Compute the precedence for matching a provided url
|
||||||
// /api/template/{id} == 1.13
|
/// </summary>
|
||||||
// /api/{id:int} == 1.2
|
/// <example>
|
||||||
// /api/template/{id:int} == 1.12
|
/// e.g.: /api/template == 1.1
|
||||||
|
/// /api/template/{id} == 1.13
|
||||||
|
/// /api/{id:int} == 1.2
|
||||||
|
/// /api/template/{id:int} == 1.12
|
||||||
|
/// </example>
|
||||||
|
/// <param name="template">The <see cref="RouteTemplate"/> to compute precendence for.</param>
|
||||||
|
/// <returns>A <see cref="decimal"/> representing the route's precendence.</returns>
|
||||||
public static decimal ComputeInbound(RouteTemplate template)
|
public static decimal ComputeInbound(RouteTemplate template)
|
||||||
{
|
{
|
||||||
ValidateSegementLength(template.Segments.Count);
|
ValidateSegementLength(template.Segments.Count);
|
||||||
|
|
@ -61,11 +67,17 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
return precedence;
|
return precedence;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the precedence for generating a url
|
/// <summary>
|
||||||
// e.g.: /api/template == 5.5
|
/// Compute the precedence for generating a url.
|
||||||
// /api/template/{id} == 5.53
|
/// </summary>
|
||||||
// /api/{id:int} == 5.4
|
/// <example>
|
||||||
// /api/template/{id:int} == 5.54
|
/// e.g.: /api/template == 5.5
|
||||||
|
/// /api/template/{id} == 5.53
|
||||||
|
/// /api/{id:int} == 5.4
|
||||||
|
/// /api/template/{id:int} == 5.54
|
||||||
|
/// </example>
|
||||||
|
/// <param name="template">The <see cref="RouteTemplate"/> to compute precendence for.</param>
|
||||||
|
/// <returns>A <see cref="decimal"/> representing the route's precendence.</returns>
|
||||||
public static decimal ComputeOutbound(RouteTemplate template)
|
public static decimal ComputeOutbound(RouteTemplate template)
|
||||||
{
|
{
|
||||||
ValidateSegementLength(template.Segments.Count);
|
ValidateSegementLength(template.Segments.Count);
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,18 @@ using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the template for a route.
|
||||||
|
/// </summary>
|
||||||
[DebuggerDisplay("{DebuggerToString()}")]
|
[DebuggerDisplay("{DebuggerToString()}")]
|
||||||
public class RouteTemplate
|
public class RouteTemplate
|
||||||
{
|
{
|
||||||
private const string SeparatorString = "/";
|
private const string SeparatorString = "/";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="RouteTemplate"/> instance given <paramref name="other"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="RoutePattern"/> instance.</param>
|
||||||
public RouteTemplate(RoutePattern other)
|
public RouteTemplate(RoutePattern other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
|
|
@ -42,6 +49,12 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a a new <see cref="RouteTemplate" /> instance given the <paramref name="template"/> string
|
||||||
|
/// and a list of <paramref name="segments"/>. Computes the parameters in the route template.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="template">A string representation of the route template.</param>
|
||||||
|
/// <param name="segments">A list of <see cref="TemplateSegment"/>.</param>
|
||||||
public RouteTemplate(string template, List<TemplateSegment> segments)
|
public RouteTemplate(string template, List<TemplateSegment> segments)
|
||||||
{
|
{
|
||||||
if (segments == null)
|
if (segments == null)
|
||||||
|
|
@ -68,12 +81,26 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the string representation of the route template.
|
||||||
|
/// </summary>
|
||||||
public string? TemplateText { get; }
|
public string? TemplateText { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of <see cref="TemplatePart"/> that represent that parameters defined in the route template.
|
||||||
|
/// </summary>
|
||||||
public IList<TemplatePart> Parameters { get; }
|
public IList<TemplatePart> Parameters { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of <see cref="TemplateSegment"/> that compromise the route template.
|
||||||
|
/// </summary>
|
||||||
public IList<TemplateSegment> Segments { get; }
|
public IList<TemplateSegment> Segments { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="TemplateSegment"/> at a given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the element to retrieve.</param>
|
||||||
|
/// <returns>A <see cref="TemplateSegment"/> instance.</returns>
|
||||||
public TemplateSegment? GetSegment(int index)
|
public TemplateSegment? GetSegment(int index)
|
||||||
{
|
{
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
|
|
@ -109,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the <see cref="RouteTemplate"/> to the equivalent
|
/// Converts the <see cref="RouteTemplate"/> to the equivalent
|
||||||
/// <see cref="RoutePattern"/>
|
/// <see cref="RoutePattern"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A <see cref="RoutePattern"/>.</returns>
|
/// <returns>A <see cref="RoutePattern"/>.</returns>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supports processing and binding parameter values in a route template.
|
||||||
|
/// </summary>
|
||||||
public class TemplateBinder
|
public class TemplateBinder
|
||||||
{
|
{
|
||||||
private readonly UrlEncoder _urlEncoder;
|
private readonly UrlEncoder _urlEncoder;
|
||||||
|
|
@ -159,7 +162,12 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
_slots = AssignSlots(_pattern, _filters);
|
_slots = AssignSlots(_pattern, _filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1: Get the list of values we're going to try to use to match and generate this URI
|
/// <summary>
|
||||||
|
/// Generates the parameter values in the route.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ambientValues">The values associated with the current request.</param>
|
||||||
|
/// <param name="values">The route values to process.</param>
|
||||||
|
/// <returns>A <see cref="TemplateValuesResult"/> instance. Can be null.</returns>
|
||||||
public TemplateValuesResult? GetValues(RouteValueDictionary? ambientValues, RouteValueDictionary values)
|
public TemplateValuesResult? GetValues(RouteValueDictionary? ambientValues, RouteValueDictionary values)
|
||||||
{
|
{
|
||||||
// Make a new copy of the slots array, we'll use this as 'scratch' space
|
// Make a new copy of the slots array, we'll use this as 'scratch' space
|
||||||
|
|
@ -424,10 +432,14 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 1.5: Process constraints
|
// Step 1.5: Process constraints
|
||||||
//
|
/// <summary>
|
||||||
// Processes the constraints **if** they were passed in to the TemplateBinder constructor.
|
/// Processes the constraints **if** they were passed in to the TemplateBinder constructor.
|
||||||
// Returns true on success
|
/// </summary>
|
||||||
// Returns false + sets the name/constraint for logging on failure.
|
/// <param name="httpContext">The <see cref="HttpContext"/> associated with the current request.</param>
|
||||||
|
/// <param name="combinedValues">A dictionary that contains the parameters for the route.</param>
|
||||||
|
/// <param name="parameterName">The name of the parameter.</param>
|
||||||
|
/// <param name="constraint">The constraint object.</param>
|
||||||
|
/// <returns><see langword="true"/> if constraints were processed succesfully and false otherwise.</returns>
|
||||||
public bool TryProcessConstraints(HttpContext? httpContext, RouteValueDictionary combinedValues, out string? parameterName, out IRouteConstraint? constraint)
|
public bool TryProcessConstraints(HttpContext? httpContext, RouteValueDictionary combinedValues, out string? parameterName, out IRouteConstraint? constraint)
|
||||||
{
|
{
|
||||||
var constraints = _constraints;
|
var constraints = _constraints;
|
||||||
|
|
@ -447,6 +459,11 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2: If the route is a match generate the appropriate URI
|
// Step 2: If the route is a match generate the appropriate URI
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of the URI associated with the route.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="acceptedValues">A dictionary that contains the parameters for the route.</param>
|
||||||
|
/// <returns>The string representation of the route.</returns>
|
||||||
public string? BindValues(RouteValueDictionary acceptedValues)
|
public string? BindValues(RouteValueDictionary acceptedValues)
|
||||||
{
|
{
|
||||||
var context = _pool.Get();
|
var context = _pool.Get();
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ using Microsoft.AspNetCore.Http;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supports matching paths to route templates and extracting parameter values.
|
||||||
|
/// </summary>
|
||||||
public class TemplateMatcher
|
public class TemplateMatcher
|
||||||
{
|
{
|
||||||
private const string SeparatorString = "/";
|
private const string SeparatorString = "/";
|
||||||
|
|
@ -21,6 +24,11 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
private static readonly char[] Delimiters = new char[] { SeparatorChar };
|
private static readonly char[] Delimiters = new char[] { SeparatorChar };
|
||||||
private RoutePatternMatcher _routePatternMatcher;
|
private RoutePatternMatcher _routePatternMatcher;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="TemplateMatcher"/> instance given a <paramref name="template"/> and <paramref name="defaults"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="template">The <see cref="RouteTemplate"/> to compare against.</param>
|
||||||
|
/// <param name="defaults">The default values for parameters in the <paramref name="template"/>.</param>
|
||||||
public TemplateMatcher(
|
public TemplateMatcher(
|
||||||
RouteTemplate template,
|
RouteTemplate template,
|
||||||
RouteValueDictionary defaults)
|
RouteValueDictionary defaults)
|
||||||
|
|
@ -62,10 +70,23 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
_routePatternMatcher = new RoutePatternMatcher(routePattern, Defaults);
|
_routePatternMatcher = new RoutePatternMatcher(routePattern, Defaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default values for parameters in the <see cref="Template"/>.
|
||||||
|
/// </summary>
|
||||||
public RouteValueDictionary Defaults { get; }
|
public RouteValueDictionary Defaults { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="RouteTemplate"/> to match against.
|
||||||
|
/// </summary>
|
||||||
public RouteTemplate Template { get; }
|
public RouteTemplate Template { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates if the provided <paramref name="path"/> matches the <see cref="Template"/>. Populates
|
||||||
|
/// <paramref name="values"/> with parameter values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">A <see cref="PathString"/> representing the route to match.</param>
|
||||||
|
/// <param name="values">A <see cref="RouteValueDictionary"/> to populate with parameter values.</param>
|
||||||
|
/// <returns><see langword="true"/> if <paramref name="path"/> matches <see cref="Template"/>.</returns>
|
||||||
public bool TryMatch(PathString path, RouteValueDictionary values)
|
public bool TryMatch(PathString path, RouteValueDictionary values)
|
||||||
{
|
{
|
||||||
if (values == null)
|
if (values == null)
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,16 @@ using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods for parsing route template strings.
|
||||||
|
/// </summary>
|
||||||
public static class TemplateParser
|
public static class TemplateParser
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="RouteTemplate"/> for a given <paramref name="routeTemplate"/> string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="routeTemplate">A string representation of the route template.</param>
|
||||||
|
/// <returns>A <see cref="RouteTemplate"/> instance.</returns>
|
||||||
public static RouteTemplate Parse(string routeTemplate)
|
public static RouteTemplate Parse(string routeTemplate)
|
||||||
{
|
{
|
||||||
if (routeTemplate == null)
|
if (routeTemplate == null)
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,23 @@ using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a part of a route template segment.
|
||||||
|
/// </summary>
|
||||||
[DebuggerDisplay("{DebuggerToString()}")]
|
[DebuggerDisplay("{DebuggerToString()}")]
|
||||||
public class TemplatePart
|
public class TemplatePart
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="TemplatePart"/> instance.
|
||||||
|
/// </summary>
|
||||||
public TemplatePart()
|
public TemplatePart()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="TemplatePart"/> instance given a <paramref name="other"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="RoutePatternPart"/> instance representing the route part.</param>
|
||||||
public TemplatePart(RoutePatternPart other)
|
public TemplatePart(RoutePatternPart other)
|
||||||
{
|
{
|
||||||
IsLiteral = other.IsLiteral || other.IsSeparator;
|
IsLiteral = other.IsLiteral || other.IsSeparator;
|
||||||
|
|
@ -47,6 +57,11 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a <see cref="TemplatePart"/> representing a literal route part.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The text of the literate route part.</param>
|
||||||
|
/// <returns>A <see cref="TemplatePart"/> instance.</returns>
|
||||||
public static TemplatePart CreateLiteral(string text)
|
public static TemplatePart CreateLiteral(string text)
|
||||||
{
|
{
|
||||||
return new TemplatePart()
|
return new TemplatePart()
|
||||||
|
|
@ -56,6 +71,15 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="TemplatePart"/> representing a paramter part.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the parameter.</param>
|
||||||
|
/// <param name="isCatchAll"><see langword="true"/> if the parameter is a catch-all parameter.</param>
|
||||||
|
/// <param name="isOptional"><see langword="true"/> if the parameter is an optional parameter.</param>
|
||||||
|
/// <param name="defaultValue">The default value of the parameter.</param>
|
||||||
|
/// <param name="inlineConstraints">A collection of constraints associated with the parameter.</param>
|
||||||
|
/// <returns>A <see cref="TemplatePart"/> instance.</returns>
|
||||||
public static TemplatePart CreateParameter(
|
public static TemplatePart CreateParameter(
|
||||||
string name,
|
string name,
|
||||||
bool isCatchAll,
|
bool isCatchAll,
|
||||||
|
|
@ -79,14 +103,41 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see langword="true"/> if the route part is is a catch-all part (e.g. /*).
|
||||||
|
/// </summary>
|
||||||
public bool IsCatchAll { get; private set; }
|
public bool IsCatchAll { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see langword="true"/> if the route part is represents a literal value.
|
||||||
|
/// </summary>
|
||||||
public bool IsLiteral { get; private set; }
|
public bool IsLiteral { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see langword="true"/> if the route part represents a parameterized value.
|
||||||
|
/// </summary>
|
||||||
public bool IsParameter { get; private set; }
|
public bool IsParameter { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see langword="true"/> if the route part represents an optional part.
|
||||||
|
/// </summary>
|
||||||
public bool IsOptional { get; private set; }
|
public bool IsOptional { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// <see langword="true"/> if the route part represents an optional seperator.
|
||||||
|
/// </summary>
|
||||||
public bool IsOptionalSeperator { get; set; }
|
public bool IsOptionalSeperator { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the route parameter. Can be null.
|
||||||
|
/// </summary>
|
||||||
public string? Name { get; private set; }
|
public string? Name { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The textual representation of the route paramter. Can be null. Used to represent route seperators and literal parts.
|
||||||
|
/// </summary>
|
||||||
public string? Text { get; private set; }
|
public string? Text { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The default value for route paramters. Can be null.
|
||||||
|
/// </summary>
|
||||||
public object? DefaultValue { get; private set; }
|
public object? DefaultValue { get; private set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The constraints associates with a route paramter.
|
||||||
|
/// </summary>
|
||||||
public IEnumerable<InlineConstraint> InlineConstraints { get; private set; } = Enumerable.Empty<InlineConstraint>();
|
public IEnumerable<InlineConstraint> InlineConstraints { get; private set; } = Enumerable.Empty<InlineConstraint>();
|
||||||
|
|
||||||
internal string? DebuggerToString()
|
internal string? DebuggerToString()
|
||||||
|
|
@ -101,6 +152,10 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="RoutePatternPart"/> for the route part designated by the <see cref="TemplatePart"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="RoutePatternPart"/> instance.</returns>
|
||||||
public RoutePatternPart ToRoutePatternPart()
|
public RoutePatternPart ToRoutePatternPart()
|
||||||
{
|
{
|
||||||
if (IsLiteral && IsOptionalSeperator)
|
if (IsLiteral && IsOptionalSeperator)
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,24 @@ using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a segment of a route template.
|
||||||
|
/// </summary>
|
||||||
[DebuggerDisplay("{DebuggerToString()}")]
|
[DebuggerDisplay("{DebuggerToString()}")]
|
||||||
public class TemplateSegment
|
public class TemplateSegment
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="TemplateSegment"/> instance.
|
||||||
|
/// </summary>
|
||||||
public TemplateSegment()
|
public TemplateSegment()
|
||||||
{
|
{
|
||||||
Parts = new List<TemplatePart>();
|
Parts = new List<TemplatePart>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="TemplateSegment"/> instance given another <see cref="RoutePatternPathSegment"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">A <see cref="RoutePatternPathSegment"/> instance.</param>
|
||||||
public TemplateSegment(RoutePatternPathSegment other)
|
public TemplateSegment(RoutePatternPathSegment other)
|
||||||
{
|
{
|
||||||
if (other == null)
|
if (other == null)
|
||||||
|
|
@ -32,8 +42,14 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see langword="true"/> if the segment contains a single entry.
|
||||||
|
/// </summary>
|
||||||
public bool IsSimple => Parts.Count == 1;
|
public bool IsSimple => Parts.Count == 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the list of individual parts in the template segment.
|
||||||
|
/// </summary>
|
||||||
public List<TemplatePart> Parts { get; }
|
public List<TemplatePart> Parts { get; }
|
||||||
|
|
||||||
internal string DebuggerToString()
|
internal string DebuggerToString()
|
||||||
|
|
@ -41,6 +57,10 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
return string.Join(string.Empty, Parts.Select(p => p.DebuggerToString()));
|
return string.Join(string.Empty, Parts.Select(p => p.DebuggerToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="RoutePatternPathSegment"/> for the template segment.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A <see cref="RoutePatternPathSegment"/> instance.</returns>
|
||||||
public RoutePatternPathSegment ToRoutePatternPathSegment()
|
public RoutePatternPathSegment ToRoutePatternPathSegment()
|
||||||
{
|
{
|
||||||
var parts = Parts.Select(p => p.ToRoutePatternPart());
|
var parts = Parts.Select(p => p.ToRoutePatternPart());
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TreeRouter : IRouter
|
public class TreeRouter : IRouter
|
||||||
{
|
{
|
||||||
// Key used by routing and action selection to match an attribute route entry to a
|
/// <summary>
|
||||||
// group of action descriptors.
|
/// Key used by routing and action selection to match an attribute
|
||||||
|
/// route entry to agroup of action descriptors.
|
||||||
|
/// </summary>
|
||||||
public static readonly string RouteGroupKey = "!__route_group";
|
public static readonly string RouteGroupKey = "!__route_group";
|
||||||
|
|
||||||
private readonly LinkGenerationDecisionTree _linkGenerationTree;
|
private readonly LinkGenerationDecisionTree _linkGenerationTree;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue