зеркало из https://github.com/aspnet/Routing.git
Constraints
This commit is contained in:
Родитель
cf16d6cba7
Коммит
a917cbd577
|
@ -1,21 +1,22 @@
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
using Microsoft.AspNet.Routing;
|
||||
|
||||
namespace RoutingSample.Web
|
||||
{
|
||||
public class HttpContextRouteEndpoint : IRouter
|
||||
public class DelegateRouteEndpoint : IRouter
|
||||
{
|
||||
private readonly RequestDelegate _appFunc;
|
||||
public delegate Task RoutedDelegate(RouteContext context);
|
||||
|
||||
public HttpContextRouteEndpoint(RequestDelegate appFunc)
|
||||
private readonly RoutedDelegate _appFunc;
|
||||
|
||||
public DelegateRouteEndpoint(RoutedDelegate appFunc)
|
||||
{
|
||||
_appFunc = appFunc;
|
||||
}
|
||||
|
||||
public async Task RouteAsync(RouteContext context)
|
||||
{
|
||||
await _appFunc(context.HttpContext);
|
||||
await _appFunc(context);
|
||||
context.IsHandled = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace RoutingSample.Web
|
||||
{
|
||||
public static class DictionaryExtensions
|
||||
{
|
||||
public static string Print(this IDictionary<string, object> routeValues)
|
||||
{
|
||||
var values = routeValues.Select(kvp => kvp.Key + ":" + kvp.Value.ToString());
|
||||
|
||||
return string.Join(" ", values);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Microsoft.AspNet.Abstractions;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
using Microsoft.AspNet.Routing;
|
||||
|
||||
namespace RoutingSample.Web
|
||||
|
@ -9,11 +10,23 @@ namespace RoutingSample.Web
|
|||
{
|
||||
var routes = builder.UseRouter();
|
||||
|
||||
var endpoint1 = new HttpContextRouteEndpoint(async (context) => await context.Response.WriteAsync("match1"));
|
||||
var endpoint2 = new HttpContextRouteEndpoint(async (context) => await context.Response.WriteAsync("Hello, World!"));
|
||||
var endpoint1 = new DelegateRouteEndpoint(async (context) =>
|
||||
await context.HttpContext.Response.WriteAsync(
|
||||
"match1, route values -" + context.Values.Print()));
|
||||
var endpoint2 = new DelegateRouteEndpoint(async (context) =>
|
||||
await context.HttpContext.Response.WriteAsync("Hello, World!"));
|
||||
|
||||
routes.DefaultHandler = endpoint1;
|
||||
routes.AddPrefixRoute("api/store");
|
||||
|
||||
routes.MapRoute("api/constraint/{controller}", null, new { controller = "my.*" });
|
||||
routes.MapRoute("api/rconstraint/{controller}",
|
||||
new { foo = "Bar" },
|
||||
new { controller = new RegexConstraint("^(my.*)$") });
|
||||
routes.MapRoute("api/r2constraint/{controller}",
|
||||
new { foo = "Bar2" },
|
||||
new { controller = new RegexConstraint(new Regex("^(my.*)$")) });
|
||||
|
||||
routes.MapRoute("api/{controller}/{*extra}", new { controller = "Store" });
|
||||
|
||||
routes.AddPrefixRoute("hello/world", endpoint2);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IRouteConstraint
|
||||
{
|
||||
bool Match([NotNull] HttpContext httpContext,
|
||||
[NotNull] IRouter route,
|
||||
[NotNull] string routeKey,
|
||||
[NotNull] IDictionary<string, object> values,
|
||||
RouteDirection routeDirection);
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IRouteValues
|
||||
{
|
||||
IDictionary<string, object> Values
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
|
||||
internal sealed class NotNullAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RegexConstraint : IRouteConstraint
|
||||
{
|
||||
public RegexConstraint([NotNull] Regex regex)
|
||||
{
|
||||
Constraint = regex;
|
||||
}
|
||||
|
||||
public RegexConstraint([NotNull] string regexPattern)
|
||||
{
|
||||
Constraint = new Regex(regexPattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
public Regex Constraint { get; private set; }
|
||||
|
||||
public bool Match([NotNull] HttpContext httpContext,
|
||||
[NotNull] IRouter route,
|
||||
[NotNull] string routeKey,
|
||||
[NotNull] IDictionary<string, object> routeValues,
|
||||
RouteDirection routeDirection)
|
||||
{
|
||||
object routeValue;
|
||||
|
||||
if (routeValues.TryGetValue(routeKey, out routeValue)
|
||||
&& routeValue != null)
|
||||
{
|
||||
var parameterValueString = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
|
||||
|
||||
return Constraint.IsMatch(parameterValueString);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
|
@ -27,7 +27,39 @@ namespace Microsoft.AspNet.Routing
|
|||
throw new ArgumentException("DefaultHandler must be set.");
|
||||
}
|
||||
|
||||
routes.Add(new TemplateRoute(routes.DefaultHandler, template, defaults));
|
||||
routes.Add(new TemplateRoute(routes.DefaultHandler, template, defaults, null));
|
||||
return routes;
|
||||
}
|
||||
|
||||
public static IRouteCollection MapRoute(this IRouteCollection routes, string template, object defaults, object constraints)
|
||||
{
|
||||
MapRoute(routes, template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints));
|
||||
return routes;
|
||||
}
|
||||
|
||||
public static IRouteCollection MapRoute(this IRouteCollection routes, string template, object defaults,
|
||||
IDictionary<string, object> constraints)
|
||||
{
|
||||
MapRoute(routes, template, new RouteValueDictionary(defaults), constraints);
|
||||
return routes;
|
||||
}
|
||||
|
||||
public static IRouteCollection MapRoute(this IRouteCollection routes, string template,
|
||||
IDictionary<string, object> defaults, object constraints)
|
||||
{
|
||||
MapRoute(routes, template, defaults, new RouteValueDictionary(constraints));
|
||||
return routes;
|
||||
}
|
||||
|
||||
public static IRouteCollection MapRoute(this IRouteCollection routes, string template,
|
||||
IDictionary<string, object> defaults, IDictionary<string, object> constraints)
|
||||
{
|
||||
if (routes.DefaultHandler == null)
|
||||
{
|
||||
throw new ArgumentException("DefaultHandler must be set.");
|
||||
}
|
||||
|
||||
routes.Add(new TemplateRoute(routes.DefaultHandler, template, defaults, constraints));
|
||||
return routes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RouteConstraintBuilder
|
||||
{
|
||||
public static IDictionary<string, IRouteConstraint>
|
||||
BuildConstraints(IDictionary<string, object> inputConstraints)
|
||||
{
|
||||
if (inputConstraints == null || inputConstraints.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var constraints = new Dictionary<string, IRouteConstraint>(inputConstraints.Count, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var kvp in inputConstraints)
|
||||
{
|
||||
var constraint = kvp.Value as IRouteConstraint;
|
||||
|
||||
if (constraint == null)
|
||||
{
|
||||
var regexPattern = kvp.Value as string;
|
||||
|
||||
if (regexPattern == null)
|
||||
{
|
||||
throw new InvalidOperationException("Constraint can be a valid regex string or an IRouteConstraint");
|
||||
}
|
||||
|
||||
var constraintsRegEx = "^(" + regexPattern + ")$";
|
||||
|
||||
constraint = new RegexConstraint(constraintsRegEx);
|
||||
}
|
||||
|
||||
constraints.Add(kvp.Key, constraint);
|
||||
}
|
||||
|
||||
return constraints;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public static class RouteConstraintMatcher
|
||||
{
|
||||
public static bool Match([NotNull] IDictionary<string, IRouteConstraint> constraints,
|
||||
[NotNull] IDictionary<string, object> routeValues,
|
||||
[NotNull] HttpContext httpContext,
|
||||
[NotNull] IRouter route,
|
||||
[NotNull] RouteDirection routeDirection)
|
||||
{
|
||||
if (constraints == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var kvp in constraints)
|
||||
{
|
||||
var constraint = kvp.Value;
|
||||
if (!constraint.Match(httpContext, route, kvp.Key, routeValues, routeDirection))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public enum RouteDirection
|
||||
{
|
||||
IncomingRequest,
|
||||
UrlGeneration,
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RouteValues : IRouteValues
|
||||
{
|
||||
public RouteValues(IDictionary<string, object> values)
|
||||
{
|
||||
Values = values;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Values
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,27 +2,26 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Abstractions;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Template
|
||||
{
|
||||
public class TemplateRoute : IRouter
|
||||
{
|
||||
private readonly IDictionary<string, object> _defaults;
|
||||
private readonly IDictionary<string, IRouteConstraint> _constraints;
|
||||
private readonly IRouter _target;
|
||||
private readonly Template _parsedTemplate;
|
||||
private readonly string _routeTemplate;
|
||||
private readonly TemplateMatcher _matcher;
|
||||
private readonly TemplateBinder _binder;
|
||||
|
||||
public TemplateRoute(IRouter target, string routeTemplate)
|
||||
: this(target, routeTemplate, null)
|
||||
: this(target, routeTemplate, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public TemplateRoute(IRouter target, string routeTemplate, IDictionary<string, object> defaults)
|
||||
public TemplateRoute(IRouter target, string routeTemplate, IDictionary<string, object> defaults,
|
||||
IDictionary<string, object> constraints)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
|
@ -32,11 +31,12 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
_target = target;
|
||||
_routeTemplate = routeTemplate ?? string.Empty;
|
||||
_defaults = defaults ?? new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
_constraints = RouteConstraintBuilder.BuildConstraints(constraints);
|
||||
|
||||
// The parser will throw for invalid routes.
|
||||
_parsedTemplate = TemplateParser.Parse(RouteTemplate);
|
||||
var parsedTemplate = TemplateParser.Parse(RouteTemplate);
|
||||
|
||||
_matcher = new TemplateMatcher(_parsedTemplate);
|
||||
_matcher = new TemplateMatcher(parsedTemplate);
|
||||
_binder = new TemplateBinder(_parsedTemplate, _defaults);
|
||||
}
|
||||
|
||||
|
@ -74,9 +74,16 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
// Not currently doing anything to clean this up if it's not a match. Consider hardening this.
|
||||
context.Values = values;
|
||||
|
||||
if (RouteConstraintMatcher.Match(_constraints,
|
||||
values,
|
||||
context.HttpContext,
|
||||
this,
|
||||
RouteDirection.IncomingRequest))
|
||||
{
|
||||
await _target.RouteAsync(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string GetVirtualPath(VirtualPathContext context)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"version": "0.1-alpha-*",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Abstractions": "0.1-alpha-*"
|
||||
"Microsoft.AspNet.Abstractions": "0.1-alpha-*",
|
||||
"Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*"
|
||||
},
|
||||
"configurations": {
|
||||
"net45": {},
|
||||
|
@ -19,6 +20,9 @@
|
|||
"System.Runtime": "4.0.20.0",
|
||||
"System.Runtime.Extensions": "4.0.10.0",
|
||||
"System.Text.RegularExpressions": "4.0.0.0",
|
||||
"System.Runtime.Hosting": "3.9.0.0",
|
||||
"System.Runtime.InteropServices": "4.0.10.0",
|
||||
"System.Text.Encoding": "4.0.10.0",
|
||||
"System.Threading.Tasks": "4.0.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests
|
|||
|
||||
private static TemplateRoute CreateRoute(string template, object defaults, bool accept = true)
|
||||
{
|
||||
return new TemplateRoute(CreateTarget(accept), template, new RouteValueDictionary(defaults));
|
||||
return new TemplateRoute(CreateTarget(accept), template, new RouteValueDictionary(defaults), null);
|
||||
}
|
||||
|
||||
private static IRouter CreateTarget(bool accept = true)
|
||||
|
|
Загрузка…
Ссылка в новой задаче