diff --git a/src/Microsoft.AspNetCore.Routing.Abstractions/EndpointMetadataCollection.cs b/src/Microsoft.AspNetCore.Routing.Abstractions/EndpointMetadataCollection.cs index ee12d0b8e7..4ca653a8fa 100644 --- a/src/Microsoft.AspNetCore.Routing.Abstractions/EndpointMetadataCollection.cs +++ b/src/Microsoft.AspNetCore.Routing.Abstractions/EndpointMetadataCollection.cs @@ -112,8 +112,7 @@ namespace Microsoft.AspNetCore.Routing var items = new List(); for (var i = 0; i < _items.Length; i++) { - var item = _items[i] as T; - if (item != null) + if (_items[i] is T item) { items.Add(item); } @@ -150,19 +149,18 @@ namespace Microsoft.AspNetCore.Routing // Intentionally not readonly to prevent defensive struct copies private object[] _items; private int _index; - private object _current; internal Enumerator(EndpointMetadataCollection collection) { _items = collection._items; _index = 0; - _current = null; + Current = null; } /// /// Gets the element at the current position of the enumerator /// - public object Current => _current; + public object Current { get; private set; } /// /// Releases all resources used by the . @@ -182,11 +180,11 @@ namespace Microsoft.AspNetCore.Routing { if (_index < _items.Length) { - _current = _items[_index++]; + Current = _items[_index++]; return true; } - _current = null; + Current = null; return false; } @@ -196,7 +194,7 @@ namespace Microsoft.AspNetCore.Routing public void Reset() { _index = 0; - _current = null; + Current = null; } } } diff --git a/src/Microsoft.AspNetCore.Routing.Abstractions/RouteValueDictionary.cs b/src/Microsoft.AspNetCore.Routing.Abstractions/RouteValueDictionary.cs index 182147b9af..2d30f6f25f 100644 --- a/src/Microsoft.AspNetCore.Routing.Abstractions/RouteValueDictionary.cs +++ b/src/Microsoft.AspNetCore.Routing.Abstractions/RouteValueDictionary.cs @@ -222,13 +222,7 @@ namespace Microsoft.AspNetCore.Routing } } - IEnumerable IReadOnlyDictionary.Keys - { - get - { - return Keys; - } - } + IEnumerable IReadOnlyDictionary.Keys => Keys; /// public ICollection Values @@ -248,13 +242,7 @@ namespace Microsoft.AspNetCore.Routing } } - IEnumerable IReadOnlyDictionary.Values - { - get - { - return Values; - } - } + IEnumerable IReadOnlyDictionary.Values => Values; /// void ICollection>.Add(KeyValuePair item) @@ -565,7 +553,7 @@ namespace Microsoft.AspNetCore.Routing internal class PropertyStorage { - private static readonly PropertyCache _propertyCache = new PropertyCache(); + private static readonly ConcurrentDictionary _propertyCache = new ConcurrentDictionary(); public readonly object Value; public readonly PropertyHelper[] Properties; @@ -606,9 +594,5 @@ namespace Microsoft.AspNetCore.Routing } } } - - private class PropertyCache : ConcurrentDictionary - { - } } } diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs index c6d80b0a06..80c2dfd801 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePattern.cs @@ -21,10 +21,10 @@ namespace Microsoft.AspNetCore.Routing.Patterns internal RoutePattern( string rawText, - Dictionary defaults, - Dictionary> constraints, - RoutePatternParameterPart[] parameters, - RoutePatternPathSegment[] pathSegments) + IReadOnlyDictionary defaults, + IReadOnlyDictionary> constraints, + IReadOnlyList parameters, + IReadOnlyList pathSegments) { Debug.Assert(defaults != null); Debug.Assert(constraints != null); diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs index 44dd675543..f34007481e 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternFactory.cs @@ -298,19 +298,35 @@ namespace Microsoft.AspNetCore.Routing.Patterns rawText, updatedDefaults, updatedConstraints.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value.ToArray()), - parameters.ToArray(), - updatedSegments.ToArray()); + parameters, + updatedSegments); RoutePatternPathSegment VisitSegment(RoutePatternPathSegment segment) { - var updatedParts = new RoutePatternPart[segment.Parts.Count]; + RoutePatternPart[] updatedParts = null; for (var i = 0; i < segment.Parts.Count; i++) { var part = segment.Parts[i]; - updatedParts[i] = VisitPart(part); + var updatedPart = VisitPart(part); + + if (part != updatedPart) + { + if (updatedParts == null) + { + updatedParts = segment.Parts.ToArray(); + } + + updatedParts[i] = updatedPart; + } } - return SegmentCore(updatedParts); + if (updatedParts == null) + { + // Segment has not changed + return segment; + } + + return new RoutePatternPathSegment(updatedParts); } RoutePatternPart VisitPart(RoutePatternPart part) @@ -357,6 +373,14 @@ namespace Microsoft.AspNetCore.Routing.Patterns parameterConstraints.AddRange(parameter.Constraints); } + if (Equals(parameter.Default, @default) + && parameter.Constraints.Count == 0 + && (parameterConstraints?.Count ?? 0) == 0) + { + // Part has not changed + return part; + } + return ParameterPartCore( parameter.Name, @default, diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs index 0af65b286c..990d1854fc 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternParser.cs @@ -138,7 +138,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns if (IsSegmentValid(context, parts)) { - segments.Add(new RoutePatternPathSegment(parts.ToArray())); + segments.Add(new RoutePatternPathSegment(parts)); return true; } else diff --git a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs index 1fd65f45d7..4e7b010518 100644 --- a/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs +++ b/src/Microsoft.AspNetCore.Routing/Patterns/RoutePatternPathSegment.cs @@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Patterns [DebuggerDisplay("{DebuggerToString()}")] public sealed class RoutePatternPathSegment { - internal RoutePatternPathSegment(RoutePatternPart[] parts) + internal RoutePatternPathSegment(IReadOnlyList parts) { Parts = parts; }