aspnetcore/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs

110 lines
3.8 KiB
C#

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
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 string _routeTemplate;
private readonly TemplateMatcher _matcher;
private readonly TemplateBinder _binder;
public TemplateRoute(IRouter target, string routeTemplate)
: this(target, routeTemplate, null, null)
{
}
public TemplateRoute([NotNull] IRouter target, string routeTemplate, IDictionary<string, object> defaults,
IDictionary<string, object> constraints)
{
_target = target;
_routeTemplate = routeTemplate ?? string.Empty;
_defaults = defaults ?? new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
_constraints = RouteConstraintBuilder.BuildConstraints(constraints, _routeTemplate);
// The parser will throw for invalid routes.
var parsedTemplate = TemplateParser.Parse(RouteTemplate);
_matcher = new TemplateMatcher(parsedTemplate);
_binder = new TemplateBinder(_parsedTemplate, _defaults);
}
public IDictionary<string, object> Defaults
{
get { return _defaults; }
}
public string RouteTemplate
{
get { return _routeTemplate; }
}
public async virtual Task RouteAsync([NotNull] RouteContext context)
{
var requestPath = context.RequestPath;
if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
{
requestPath = requestPath.Substring(1);
}
var values = _matcher.Match(requestPath, _defaults);
if (values == null)
{
// If we got back a null value set, that means the URI did not match
return;
}
else
{
// 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)
{
var values = _binder.GetAcceptedValues(context.AmbientValues, context.Values);
if (values == null)
{
// We're missing one the required values for this route.
return null;
}
// Validate that the target can accept these values.
var path = _target.GetVirtualPath(context);
if (path != null)
{
// If the target generates a value then that can short circuit.
return path;
}
else if (!context.IsBound)
{
// The target has rejected these values.
return null;
}
path = _binder.BindValues(values);
if (path == null)
{
context.IsBound = false;
}
return path;
}
}
}