Reduce allocation in URL generation
This change optimizes our a per-operation dictionary that really can just be cached for the whole app's lifetime.
This commit is contained in:
parent
37c167aa74
commit
813171a016
|
|
@ -14,14 +14,15 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
{
|
||||
public class TemplateBinder
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, object> _defaults;
|
||||
private readonly RouteValueDictionary _defaults;
|
||||
private readonly RouteValueDictionary _filters;
|
||||
private readonly RouteTemplate _template;
|
||||
private readonly UrlEncoder _urlEncoder;
|
||||
|
||||
public TemplateBinder(
|
||||
RouteTemplate template,
|
||||
UrlEncoder urlEncoder,
|
||||
IReadOnlyDictionary<string, object> defaults)
|
||||
RouteValueDictionary defaults)
|
||||
{
|
||||
if (template == null)
|
||||
{
|
||||
|
|
@ -36,6 +37,14 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
_template = template;
|
||||
_urlEncoder = urlEncoder;
|
||||
_defaults = defaults;
|
||||
|
||||
// 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.
|
||||
_filters = new RouteValueDictionary(_defaults);
|
||||
foreach (var parameter in _template.Parameters)
|
||||
{
|
||||
_filters.Remove(parameter.Name);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1: Get the list of values we're going to try to use to match and generate this URI
|
||||
|
|
@ -132,25 +141,22 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
|
||||
// Any default values that don't appear as parameters are treated like filters. Any new values
|
||||
// provided must match these defaults.
|
||||
if (context.Filters != null)
|
||||
foreach (var filter in _filters)
|
||||
{
|
||||
foreach (var filter in context.Filters)
|
||||
var parameter = GetParameter(filter.Key);
|
||||
if (parameter != null)
|
||||
{
|
||||
var parameter = GetParameter(filter.Key);
|
||||
if (parameter != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
object value;
|
||||
if (values.TryGetValue(filter.Key, out value))
|
||||
object value;
|
||||
if (values.TryGetValue(filter.Key, out value))
|
||||
{
|
||||
if (!RoutePartsEqual(value, filter.Value))
|
||||
{
|
||||
if (!RoutePartsEqual(value, filter.Value))
|
||||
{
|
||||
// If there is a non-parameterized value in the route and there is a
|
||||
// new value for it and it doesn't match, this route won't match.
|
||||
return null;
|
||||
}
|
||||
// If there is a non-parameterized value in the route and there is a
|
||||
// new value for it and it doesn't match, this route won't match.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -346,21 +352,14 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
[DebuggerDisplay("{DebuggerToString(),nq}")]
|
||||
private class TemplateBindingContext
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, object> _defaults;
|
||||
|
||||
private readonly RouteValueDictionary _defaults;
|
||||
private readonly RouteValueDictionary _acceptedValues;
|
||||
private readonly RouteValueDictionary _filters;
|
||||
|
||||
public TemplateBindingContext(IReadOnlyDictionary<string, object> defaults)
|
||||
public TemplateBindingContext(RouteValueDictionary defaults)
|
||||
{
|
||||
_defaults = defaults;
|
||||
|
||||
_acceptedValues = new RouteValueDictionary();
|
||||
|
||||
if (_defaults != null)
|
||||
{
|
||||
_filters = new RouteValueDictionary(_defaults);
|
||||
}
|
||||
}
|
||||
|
||||
public RouteValueDictionary AcceptedValues
|
||||
|
|
@ -368,11 +367,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
get { return _acceptedValues; }
|
||||
}
|
||||
|
||||
public RouteValueDictionary Filters
|
||||
{
|
||||
get { return _filters; }
|
||||
}
|
||||
|
||||
public void Accept(string key, object value)
|
||||
{
|
||||
if (!_acceptedValues.ContainsKey(key))
|
||||
|
|
@ -388,7 +382,6 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
object value;
|
||||
if (_defaults != null && _defaults.TryGetValue(key, out value))
|
||||
{
|
||||
_filters.Remove(key);
|
||||
_acceptedValues.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
|
@ -400,10 +393,7 @@ namespace Microsoft.AspNet.Routing.Template
|
|||
|
||||
private string DebuggerToString()
|
||||
{
|
||||
return string.Format(
|
||||
"{{Accepted: '{0}' Filters: '{1}'}}",
|
||||
string.Join(", ", _acceptedValues.Keys),
|
||||
string.Join(", ", _filters?.Keys));
|
||||
return string.Format("{{Accepted: '{0}'}}", string.Join(", ", _acceptedValues.Keys));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests
|
|||
[MemberData(nameof(EmptyAndNullDefaultValues))]
|
||||
public void Binding_WithEmptyAndNull_DefaultValues(
|
||||
string template,
|
||||
IReadOnlyDictionary<string, object> defaults,
|
||||
RouteValueDictionary defaults,
|
||||
RouteValueDictionary values,
|
||||
string expected)
|
||||
{
|
||||
|
|
@ -255,7 +255,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests
|
|||
[MemberData(nameof(OptionalParamValues))]
|
||||
public void GetVirtualPathWithMultiSegmentWithOptionalParam(
|
||||
string template,
|
||||
IReadOnlyDictionary<string, object> defaults,
|
||||
RouteValueDictionary defaults,
|
||||
RouteValueDictionary ambientValues,
|
||||
RouteValueDictionary values,
|
||||
string expected)
|
||||
|
|
@ -1083,7 +1083,7 @@ namespace Microsoft.AspNet.Routing.Template.Tests
|
|||
|
||||
private static void RunTest(
|
||||
string template,
|
||||
IReadOnlyDictionary<string, object> defaults,
|
||||
RouteValueDictionary defaults,
|
||||
RouteValueDictionary ambientValues,
|
||||
RouteValueDictionary values,
|
||||
string expected,
|
||||
|
|
|
|||
|
|
@ -1571,9 +1571,14 @@ namespace Microsoft.AspNet.Routing.Tree
|
|||
var entry = new TreeRouteLinkGenerationEntry();
|
||||
entry.Template = TemplateParser.Parse(template);
|
||||
|
||||
var defaults = entry.Template.Parameters
|
||||
.Where(p => p.DefaultValue != null)
|
||||
.ToDictionary(p => p.Name, p => p.DefaultValue);
|
||||
var defaults = new RouteValueDictionary();
|
||||
foreach (var parameter in entry.Template.Parameters)
|
||||
{
|
||||
if (parameter.DefaultValue != null)
|
||||
{
|
||||
defaults.Add(parameter.Name, parameter.DefaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
var constraintBuilder = new RouteConstraintBuilder(CreateConstraintResolver(), template);
|
||||
foreach (var parameter in entry.Template.Parameters)
|
||||
|
|
|
|||
Loading…
Reference in New Issue