Use RoutePattern in TemplateBinder
This commit is contained in:
parent
e09b88ebd6
commit
085a0b808e
|
|
@ -105,7 +105,7 @@ namespace Microsoft.AspNetCore.Routing
|
||||||
var templateBinder = new TemplateBinder(
|
var templateBinder = new TemplateBinder(
|
||||||
UrlEncoder.Default,
|
UrlEncoder.Default,
|
||||||
_uriBuildingContextPool,
|
_uriBuildingContextPool,
|
||||||
new RouteTemplate(endpoint.RoutePattern),
|
endpoint.RoutePattern,
|
||||||
new RouteValueDictionary(endpoint.RoutePattern.Defaults));
|
new RouteValueDictionary(endpoint.RoutePattern.Defaults));
|
||||||
|
|
||||||
var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
var routeValuesAddressMetadata = endpoint.Metadata.GetMetadata<IRouteValuesAddressMetadata>();
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using Microsoft.AspNetCore.Routing.Internal;
|
using Microsoft.AspNetCore.Routing.Internal;
|
||||||
|
using Microsoft.AspNetCore.Routing.Patterns;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
using Microsoft.Extensions.ObjectPool;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Routing.Template
|
namespace Microsoft.AspNetCore.Routing.Template
|
||||||
|
|
@ -19,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
|
|
||||||
private readonly RouteValueDictionary _defaults;
|
private readonly RouteValueDictionary _defaults;
|
||||||
private readonly RouteValueDictionary _filters;
|
private readonly RouteValueDictionary _filters;
|
||||||
private readonly RouteTemplate _template;
|
private readonly RoutePattern _pattern;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of <see cref="TemplateBinder"/>.
|
/// Creates a new instance of <see cref="TemplateBinder"/>.
|
||||||
|
|
@ -33,6 +34,22 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
ObjectPool<UriBuildingContext> pool,
|
ObjectPool<UriBuildingContext> pool,
|
||||||
RouteTemplate template,
|
RouteTemplate template,
|
||||||
RouteValueDictionary defaults)
|
RouteValueDictionary defaults)
|
||||||
|
: this(urlEncoder, pool, template?.ToRoutePattern(), defaults)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="TemplateBinder"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="urlEncoder">The <see cref="UrlEncoder"/>.</param>
|
||||||
|
/// <param name="pool">The <see cref="ObjectPool{T}"/>.</param>
|
||||||
|
/// <param name="pattern">The <see cref="RoutePattern"/> to bind values to.</param>
|
||||||
|
/// <param name="defaults">The default values for <paramref name="pattern"/>.</param>
|
||||||
|
public TemplateBinder(
|
||||||
|
UrlEncoder urlEncoder,
|
||||||
|
ObjectPool<UriBuildingContext> pool,
|
||||||
|
RoutePattern pattern,
|
||||||
|
RouteValueDictionary defaults)
|
||||||
{
|
{
|
||||||
if (urlEncoder == null)
|
if (urlEncoder == null)
|
||||||
{
|
{
|
||||||
|
|
@ -44,20 +61,20 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
throw new ArgumentNullException(nameof(pool));
|
throw new ArgumentNullException(nameof(pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template == null)
|
if (pattern == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(template));
|
throw new ArgumentNullException(nameof(pattern));
|
||||||
}
|
}
|
||||||
|
|
||||||
_urlEncoder = urlEncoder;
|
_urlEncoder = urlEncoder;
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
_template = template;
|
_pattern = pattern;
|
||||||
_defaults = defaults;
|
_defaults = defaults;
|
||||||
|
|
||||||
// Any default that doesn't have a corresponding parameter is a 'filter' and if a value
|
// Any default that doesn't have a corresponding parameter is a 'filter' and if a value
|
||||||
// is provided for that 'filter' it must match the value in defaults.
|
// is provided for that 'filter' it must match the value in defaults.
|
||||||
_filters = new RouteValueDictionary(_defaults);
|
_filters = new RouteValueDictionary(_defaults);
|
||||||
foreach (var parameter in _template.Parameters)
|
foreach (var parameter in _pattern.Parameters)
|
||||||
{
|
{
|
||||||
_filters.Remove(parameter.Name);
|
_filters.Remove(parameter.Name);
|
||||||
}
|
}
|
||||||
|
|
@ -149,36 +166,43 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
|
|
||||||
private string BindValues(UriBuildingContext context, RouteValueDictionary acceptedValues)
|
private string BindValues(UriBuildingContext context, RouteValueDictionary acceptedValues)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _template.Segments.Count; i++)
|
for (var i = 0; i < _pattern.PathSegments.Count; i++)
|
||||||
{
|
{
|
||||||
Debug.Assert(context.BufferState == SegmentState.Beginning);
|
Debug.Assert(context.BufferState == SegmentState.Beginning);
|
||||||
Debug.Assert(context.UriState == SegmentState.Beginning);
|
Debug.Assert(context.UriState == SegmentState.Beginning);
|
||||||
|
|
||||||
var segment = _template.Segments[i];
|
var segment = _pattern.PathSegments[i];
|
||||||
|
|
||||||
for (var j = 0; j < segment.Parts.Count; j++)
|
for (var j = 0; j < segment.Parts.Count; j++)
|
||||||
{
|
{
|
||||||
var part = segment.Parts[j];
|
var part = segment.Parts[j];
|
||||||
|
|
||||||
if (part.IsLiteral)
|
if (part is RoutePatternLiteralPart literalPart)
|
||||||
{
|
{
|
||||||
if (!context.Accept(part.Text))
|
if (!context.Accept(literalPart.Content))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (part.IsParameter)
|
else if (part is RoutePatternSeparatorPart separatorPart)
|
||||||
|
{
|
||||||
|
if (!context.Accept(separatorPart.Content))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (part is RoutePatternParameterPart parameterPart)
|
||||||
{
|
{
|
||||||
// If it's a parameter, get its value
|
// If it's a parameter, get its value
|
||||||
var hasValue = acceptedValues.TryGetValue(part.Name, out var value);
|
var hasValue = acceptedValues.TryGetValue(parameterPart.Name, out var value);
|
||||||
if (hasValue)
|
if (hasValue)
|
||||||
{
|
{
|
||||||
acceptedValues.Remove(part.Name);
|
acceptedValues.Remove(parameterPart.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var isSameAsDefault = false;
|
var isSameAsDefault = false;
|
||||||
if (_defaults != null &&
|
if (_defaults != null &&
|
||||||
_defaults.TryGetValue(part.Name, out var defaultValue) &&
|
_defaults.TryGetValue(parameterPart.Name, out var defaultValue) &&
|
||||||
RoutePartsEqual(value, defaultValue))
|
RoutePartsEqual(value, defaultValue))
|
||||||
{
|
{
|
||||||
isSameAsDefault = true;
|
isSameAsDefault = true;
|
||||||
|
|
@ -206,9 +230,9 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
// for format, so we remove '.' and generate 5.
|
// for format, so we remove '.' and generate 5.
|
||||||
if (!context.Accept(converted))
|
if (!context.Accept(converted))
|
||||||
{
|
{
|
||||||
if (j != 0 && part.IsOptional && segment.Parts[j - 1].IsOptionalSeperator)
|
if (j != 0 && parameterPart.IsOptional && (separatorPart = segment.Parts[j - 1] as RoutePatternSeparatorPart) != null)
|
||||||
{
|
{
|
||||||
context.Remove(segment.Parts[j - 1].Text);
|
context.Remove(separatorPart.Content);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -262,20 +286,6 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TemplatePart GetParameter(string name)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < _template.Parameters.Count; i++)
|
|
||||||
{
|
|
||||||
var parameter = _template.Parameters[i];
|
|
||||||
if (string.Equals(parameter.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
return parameter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compares two objects for equality as parts of a case-insensitive path.
|
/// Compares two objects for equality as parts of a case-insensitive path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -370,9 +380,9 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
// We also handle the case where a parameter is optional but has no value - we shouldn't
|
// We also handle the case where a parameter is optional but has no value - we shouldn't
|
||||||
// accept additional parameters that appear *after* that parameter.
|
// accept additional parameters that appear *after* that parameter.
|
||||||
|
|
||||||
for (var i = 0; i < _template.Parameters.Count; i++)
|
for (var i = 0; i < _pattern.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
var parameter = _template.Parameters[i];
|
var parameter = _pattern.Parameters[i];
|
||||||
|
|
||||||
// If it's a parameter subsegment, examine the current value to see if it matches the new value
|
// If it's a parameter subsegment, examine the current value to see if it matches the new value
|
||||||
var parameterName = parameter.Name;
|
var parameterName = parameter.Name;
|
||||||
|
|
@ -436,9 +446,9 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
|
|
||||||
private void CopyParameterDefaultValues(TemplateBindingContext context)
|
private void CopyParameterDefaultValues(TemplateBindingContext context)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _template.Parameters.Count; i++)
|
for (var i = 0; i < _pattern.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
var parameter = _template.Parameters[i];
|
var parameter = _pattern.Parameters[i];
|
||||||
if (parameter.IsOptional || parameter.IsCatchAll)
|
if (parameter.IsOptional || parameter.IsCatchAll)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -456,9 +466,9 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
|
|
||||||
private bool AllRequiredParametersHaveValue(TemplateBindingContext context)
|
private bool AllRequiredParametersHaveValue(TemplateBindingContext context)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _template.Parameters.Count; i++)
|
for (var i = 0; i < _pattern.Parameters.Count; i++)
|
||||||
{
|
{
|
||||||
var parameter = _template.Parameters[i];
|
var parameter = _pattern.Parameters[i];
|
||||||
if (parameter.IsOptional || parameter.IsCatchAll)
|
if (parameter.IsOptional || parameter.IsCatchAll)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -477,7 +487,7 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
foreach (var filter in _filters)
|
foreach (var filter in _filters)
|
||||||
{
|
{
|
||||||
var parameter = GetParameter(filter.Key);
|
var parameter = _pattern.GetParameter(filter.Key);
|
||||||
if (parameter != null)
|
if (parameter != null)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -507,7 +517,7 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
{
|
{
|
||||||
if (IsRoutePartNonEmpty(kvp.Value))
|
if (IsRoutePartNonEmpty(kvp.Value))
|
||||||
{
|
{
|
||||||
var parameter = GetParameter(kvp.Key);
|
var parameter = _pattern.GetParameter(kvp.Key);
|
||||||
if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key))
|
if (parameter == null && !context.AcceptedValues.ContainsKey(kvp.Key))
|
||||||
{
|
{
|
||||||
combinedValues.Add(kvp.Key, kvp.Value);
|
combinedValues.Add(kvp.Key, kvp.Value);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue