diff --git a/src/Http/Routing/ref/Microsoft.AspNetCore.Routing.netcoreapp3.0.cs b/src/Http/Routing/ref/Microsoft.AspNetCore.Routing.netcoreapp3.0.cs index b83aa2efeb..3827225df0 100644 --- a/src/Http/Routing/ref/Microsoft.AspNetCore.Routing.netcoreapp3.0.cs +++ b/src/Http/Routing/ref/Microsoft.AspNetCore.Routing.netcoreapp3.0.cs @@ -491,71 +491,19 @@ namespace Microsoft.AspNetCore.Routing.Constraints } namespace Microsoft.AspNetCore.Routing.Internal { - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct BufferValue - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public BufferValue(string value, bool requiresEncoding) { throw null; } - public bool RequiresEncoding { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public string Value { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } public partial class DfaGraphWriter { public DfaGraphWriter(System.IServiceProvider services) { } public void Write(Microsoft.AspNetCore.Routing.EndpointDataSource dataSource, System.IO.TextWriter writer) { } } - [System.Diagnostics.DebuggerDisplayAttribute("{DebuggerDisplayString,nq}")] - public partial class LinkGenerationDecisionTree - { - public LinkGenerationDecisionTree(System.Collections.Generic.IReadOnlyList entries) { } - public System.Collections.Generic.IList GetMatches(Microsoft.AspNetCore.Routing.RouteValueDictionary values, Microsoft.AspNetCore.Routing.RouteValueDictionary ambientValues) { throw null; } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public readonly partial struct OutboundMatchResult - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public OutboundMatchResult(Microsoft.AspNetCore.Routing.Tree.OutboundMatch match, bool isFallbackMatch) { throw null; } - public bool IsFallbackMatch { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - public Microsoft.AspNetCore.Routing.Tree.OutboundMatch Match { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } - } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public partial struct PathTokenizer : System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyList, System.Collections.IEnumerable - { - private object _dummy; - private int _dummyPrimitive; - public PathTokenizer(Microsoft.AspNetCore.Http.PathString path) { throw null; } - public int Count { get { throw null; } } - public Microsoft.Extensions.Primitives.StringSegment this[int index] { get { throw null; } } - public Microsoft.AspNetCore.Routing.Internal.PathTokenizer.Enumerator GetEnumerator() { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] - public partial struct Enumerator : System.Collections.Generic.IEnumerator, System.Collections.IEnumerator, System.IDisposable - { - private object _dummy; - private int _dummyPrimitive; - public Enumerator(Microsoft.AspNetCore.Routing.Internal.PathTokenizer tokenizer) { throw null; } - public Microsoft.Extensions.Primitives.StringSegment Current { get { throw null; } } - object System.Collections.IEnumerator.Current { get { throw null; } } - public void Dispose() { } - public bool MoveNext() { throw null; } - public void Reset() { } - } - } + [System.ObsoleteAttribute("This type will be marked as internal in a future release.")] public enum SegmentState { Beginning = 0, Inside = 1, } - public partial class UriBuilderContextPooledObjectPolicy : Microsoft.Extensions.ObjectPool.IPooledObjectPolicy - { - public UriBuilderContextPooledObjectPolicy() { } - public Microsoft.AspNetCore.Routing.Internal.UriBuildingContext Create() { throw null; } - public bool Return(Microsoft.AspNetCore.Routing.Internal.UriBuildingContext obj) { throw null; } - } [System.Diagnostics.DebuggerDisplayAttribute("{DebuggerToString(),nq}")] + [System.ObsoleteAttribute("This type will be marked as internal in a future release.")] public partial class UriBuildingContext { public UriBuildingContext(System.Text.Encodings.Web.UrlEncoder urlEncoder) { } @@ -808,13 +756,21 @@ namespace Microsoft.AspNetCore.Routing.Template } public partial class TemplateBinder { + [System.ObsoleteAttribute("This constructor is obsolete and will be marked internal in a future release. Use the TemplateBinderFactory service to create TemplateBinder instances.")] public TemplateBinder(System.Text.Encodings.Web.UrlEncoder urlEncoder, Microsoft.Extensions.ObjectPool.ObjectPool pool, Microsoft.AspNetCore.Routing.Patterns.RoutePattern pattern, Microsoft.AspNetCore.Routing.RouteValueDictionary defaults, System.Collections.Generic.IEnumerable requiredKeys, System.Collections.Generic.IEnumerable> parameterPolicies) { } + [System.ObsoleteAttribute("This constructor is obsolete and will be marked internal in a furture release. Use the TemplateBinderFactory service to create TemplateBinder instances.")] public TemplateBinder(System.Text.Encodings.Web.UrlEncoder urlEncoder, Microsoft.Extensions.ObjectPool.ObjectPool pool, Microsoft.AspNetCore.Routing.Template.RouteTemplate template, Microsoft.AspNetCore.Routing.RouteValueDictionary defaults) { } public string BindValues(Microsoft.AspNetCore.Routing.RouteValueDictionary acceptedValues) { throw null; } public Microsoft.AspNetCore.Routing.Template.TemplateValuesResult GetValues(Microsoft.AspNetCore.Routing.RouteValueDictionary ambientValues, Microsoft.AspNetCore.Routing.RouteValueDictionary values) { throw null; } public static bool RoutePartsEqual(object a, object b) { throw null; } public bool TryProcessConstraints(Microsoft.AspNetCore.Http.HttpContext httpContext, Microsoft.AspNetCore.Routing.RouteValueDictionary combinedValues, out string parameterName, out Microsoft.AspNetCore.Routing.IRouteConstraint constraint) { throw null; } } + public abstract partial class TemplateBinderFactory + { + protected TemplateBinderFactory() { } + public abstract Microsoft.AspNetCore.Routing.Template.TemplateBinder Create(Microsoft.AspNetCore.Routing.Patterns.RoutePattern pattern); + public abstract Microsoft.AspNetCore.Routing.Template.TemplateBinder Create(Microsoft.AspNetCore.Routing.Template.RouteTemplate template, Microsoft.AspNetCore.Routing.RouteValueDictionary defaults); + } public partial class TemplateMatcher { public TemplateMatcher(Microsoft.AspNetCore.Routing.Template.RouteTemplate template, Microsoft.AspNetCore.Routing.RouteValueDictionary defaults) { } @@ -901,6 +857,7 @@ namespace Microsoft.AspNetCore.Routing.Tree } public partial class TreeRouteBuilder { + [System.ObsoleteAttribute("This constructor will be marked internal in a future release. Use the service provider to create instances of TreeRouteBuilder.")] public TreeRouteBuilder(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.Extensions.ObjectPool.ObjectPool objectPool, Microsoft.AspNetCore.Routing.IInlineConstraintResolver constraintResolver) { } public System.Collections.Generic.IList InboundEntries { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public System.Collections.Generic.IList OutboundEntries { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } @@ -913,6 +870,7 @@ namespace Microsoft.AspNetCore.Routing.Tree public partial class TreeRouter : Microsoft.AspNetCore.Routing.IRouter { public static readonly string RouteGroupKey; + [System.ObsoleteAttribute("This constructor will be marked obsolete in a future release. Use the TreeRouterBuilder to create instances of TreeRouter.")] public TreeRouter(Microsoft.AspNetCore.Routing.Tree.UrlMatchingTree[] trees, System.Collections.Generic.IEnumerable linkGenerationEntries, System.Text.Encodings.Web.UrlEncoder urlEncoder, Microsoft.Extensions.ObjectPool.ObjectPool objectPool, Microsoft.Extensions.Logging.ILogger routeLogger, Microsoft.Extensions.Logging.ILogger constraintLogger, int version) { } public int Version { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } public Microsoft.AspNetCore.Routing.VirtualPathData GetVirtualPath(Microsoft.AspNetCore.Routing.VirtualPathContext context) { throw null; } diff --git a/src/Http/Routing/src/Internal/ArrayBuilder.cs b/src/Http/Routing/src/ArrayBuilder.cs similarity index 97% rename from src/Http/Routing/src/Internal/ArrayBuilder.cs rename to src/Http/Routing/src/ArrayBuilder.cs index 868b3cfc27..ff20c2e64d 100644 --- a/src/Http/Routing/src/Internal/ArrayBuilder.cs +++ b/src/Http/Routing/src/ArrayBuilder.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -10,7 +10,7 @@ using System; using System.Diagnostics; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing { /// /// Helper type for avoiding allocations while building arrays. @@ -166,4 +166,4 @@ namespace Microsoft.AspNetCore.Routing.Internal _array = next; } } -} \ No newline at end of file +} diff --git a/src/Http/Routing/src/DefaultLinkGenerator.cs b/src/Http/Routing/src/DefaultLinkGenerator.cs index 21f36cac63..aae057a3ac 100644 --- a/src/Http/Routing/src/DefaultLinkGenerator.cs +++ b/src/Http/Routing/src/DefaultLinkGenerator.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Routing internal sealed class DefaultLinkGenerator : LinkGenerator, IDisposable { private readonly ParameterPolicyFactory _parameterPolicyFactory; - private readonly ObjectPool _uriBuildingContextPool; + private readonly TemplateBinderFactory _binderFactory; private readonly ILogger _logger; private readonly IServiceProvider _serviceProvider; @@ -38,14 +38,14 @@ namespace Microsoft.AspNetCore.Routing public DefaultLinkGenerator( ParameterPolicyFactory parameterPolicyFactory, + TemplateBinderFactory binderFactory, EndpointDataSource dataSource, - ObjectPool uriBuildingContextPool, IOptions routeOptions, ILogger logger, IServiceProvider serviceProvider) { _parameterPolicyFactory = parameterPolicyFactory; - _uriBuildingContextPool = uriBuildingContextPool; + _binderFactory = binderFactory; _logger = logger; _serviceProvider = serviceProvider; @@ -282,40 +282,7 @@ namespace Microsoft.AspNetCore.Routing private TemplateBinder CreateTemplateBinder(RouteEndpoint endpoint) { - // Now create the constraints and parameter transformers from the pattern - var policies = new List<(string parameterName, IParameterPolicy policy)>(); - foreach (var kvp in endpoint.RoutePattern.ParameterPolicies) - { - var parameterName = kvp.Key; - - // It's possible that we don't have an actual route parameter, we need to support that case. - var parameter = endpoint.RoutePattern.GetParameter(parameterName); - - // Use the first parameter transformer per parameter - var foundTransformer = false; - for (var i = 0; i < kvp.Value.Count; i++) - { - var parameterPolicy = _parameterPolicyFactory.Create(parameter, kvp.Value[i]); - if (!foundTransformer && parameterPolicy is IOutboundParameterTransformer parameterTransformer) - { - policies.Add((parameterName, parameterTransformer)); - foundTransformer = true; - } - - if (parameterPolicy is IRouteConstraint constraint) - { - policies.Add((parameterName, constraint)); - } - } - } - - return new TemplateBinder( - UrlEncoder.Default, - _uriBuildingContextPool, - endpoint.RoutePattern, - new RouteValueDictionary(endpoint.RoutePattern.Defaults), - endpoint.RoutePattern.RequiredValues.Keys, - policies); + return _binderFactory.Create(endpoint.RoutePattern); } // Internal for testing diff --git a/src/Http/Routing/src/DependencyInjection/RoutingServiceCollectionExtensions.cs b/src/Http/Routing/src/DependencyInjection/RoutingServiceCollectionExtensions.cs index 94c1efdd26..8a9d10a45f 100644 --- a/src/Http/Routing/src/DependencyInjection/RoutingServiceCollectionExtensions.cs +++ b/src/Http/Routing/src/DependencyInjection/RoutingServiceCollectionExtensions.cs @@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Matching; using Microsoft.AspNetCore.Routing.Patterns; +using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Tree; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; @@ -34,6 +35,7 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddTransient(); services.TryAddTransient(); +#pragma warning disable CS0618 // Type or member is obsolete services.TryAddSingleton>(s => { var provider = s.GetRequiredService(); @@ -49,6 +51,7 @@ namespace Microsoft.Extensions.DependencyInjection var constraintResolver = s.GetRequiredService(); return new TreeRouteBuilder(loggerFactory, objectPool, constraintResolver); })); +#pragma warning restore CS0618 // Type or member is obsolete services.TryAddSingleton(typeof(RoutingMarkerService)); @@ -88,6 +91,7 @@ namespace Microsoft.Extensions.DependencyInjection // // Misc infrastructure // + services.TryAddSingleton(); services.TryAddSingleton(); return services; } diff --git a/src/Http/Routing/src/Internal/BufferValue.cs b/src/Http/Routing/src/Internal/BufferValue.cs deleted file mode 100644 index f71617038d..0000000000 --- a/src/Http/Routing/src/Internal/BufferValue.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.AspNetCore.Routing.Internal -{ - public readonly struct BufferValue - { - public BufferValue(string value, bool requiresEncoding) - { - Value = value; - RequiresEncoding = requiresEncoding; - } - - public bool RequiresEncoding { get; } - - public string Value { get; } - } -} diff --git a/src/Http/Routing/src/Internal/SegmentState.cs b/src/Http/Routing/src/Internal/SegmentState.cs index 35076a0678..6431f01059 100644 --- a/src/Http/Routing/src/Internal/SegmentState.cs +++ b/src/Http/Routing/src/Internal/SegmentState.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; + namespace Microsoft.AspNetCore.Routing.Internal { // Segments are treated as all-or-none. We should never output a partial segment. @@ -9,6 +11,7 @@ namespace Microsoft.AspNetCore.Routing.Internal // used a value for {p1}, we have to output the entire segment up to the next "/". // Otherwise we could end up with the partial segment "v1" instead of the entire // segment "v1-v2.xml". + [Obsolete("This type will be marked as internal in a future release.")] public enum SegmentState { Beginning, diff --git a/src/Http/Routing/src/Internal/UriBuildingContext.cs b/src/Http/Routing/src/Internal/UriBuildingContext.cs index 82e0b4137b..dcfde1d866 100644 --- a/src/Http/Routing/src/Internal/UriBuildingContext.cs +++ b/src/Http/Routing/src/Internal/UriBuildingContext.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Http; namespace Microsoft.AspNetCore.Routing.Internal { + [Obsolete("This type will be marked as internal in a future release.")] [DebuggerDisplay("{DebuggerToString(),nq}")] public class UriBuildingContext { @@ -321,5 +323,18 @@ namespace Microsoft.AspNetCore.Routing.Internal { return string.Format("{{Accepted: '{0}' Buffered: '{1}'}}", _path, string.Join("", _buffer)); } + + private readonly struct BufferValue + { + public BufferValue(string value, bool requiresEncoding) + { + Value = value; + RequiresEncoding = requiresEncoding; + } + + public bool RequiresEncoding { get; } + + public string Value { get; } + } } } diff --git a/src/Http/Routing/src/Internal/NullRouter.cs b/src/Http/Routing/src/NullRouter.cs similarity index 100% rename from src/Http/Routing/src/Internal/NullRouter.cs rename to src/Http/Routing/src/NullRouter.cs diff --git a/src/Http/Routing/src/Internal/ParameterPolicyActivator.cs b/src/Http/Routing/src/ParameterPolicyActivator.cs similarity index 98% rename from src/Http/Routing/src/Internal/ParameterPolicyActivator.cs rename to src/Http/Routing/src/ParameterPolicyActivator.cs index c04de5ba60..ab18e7efe8 100644 --- a/src/Http/Routing/src/Internal/ParameterPolicyActivator.cs +++ b/src/Http/Routing/src/ParameterPolicyActivator.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -9,7 +9,7 @@ using System.Reflection; using System.Text; using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing { internal static class ParameterPolicyActivator { diff --git a/src/Http/Routing/src/Internal/PathTokenizer.cs b/src/Http/Routing/src/PathTokenizer.cs similarity index 98% rename from src/Http/Routing/src/Internal/PathTokenizer.cs rename to src/Http/Routing/src/PathTokenizer.cs index 9418989fdb..307dfb1159 100644 --- a/src/Http/Routing/src/Internal/PathTokenizer.cs +++ b/src/Http/Routing/src/PathTokenizer.cs @@ -8,9 +8,9 @@ using System.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing { - public struct PathTokenizer : IReadOnlyList + internal struct PathTokenizer : IReadOnlyList { private readonly string _path; private int _count; diff --git a/src/Http/Routing/src/RouteBase.cs b/src/Http/Routing/src/RouteBase.cs index 2659e7fac4..c12eaae75b 100644 --- a/src/Http/Routing/src/RouteBase.cs +++ b/src/Http/Routing/src/RouteBase.cs @@ -246,14 +246,16 @@ namespace Microsoft.AspNetCore.Routing } } +#pragma warning disable CS0618 // Type or member is obsolete private void EnsureBinder(HttpContext context) { if (_binder == null) { - var pool = context.RequestServices.GetRequiredService>(); - _binder = new TemplateBinder(UrlEncoder.Default, pool, ParsedTemplate, Defaults); + var binderFactory = context.RequestServices.GetRequiredService(); + _binder = binderFactory.Create(ParsedTemplate, Defaults); } } +#pragma warning restore CS0618 // Type or member is obsolete private void EnsureLoggers(HttpContext context) { diff --git a/src/Http/Routing/src/Internal/RoutingMarkerService.cs b/src/Http/Routing/src/RoutingMarkerService.cs similarity index 90% rename from src/Http/Routing/src/Internal/RoutingMarkerService.cs rename to src/Http/Routing/src/RoutingMarkerService.cs index c7bed9df18..ab876b0c39 100644 --- a/src/Http/Routing/src/Internal/RoutingMarkerService.cs +++ b/src/Http/Routing/src/RoutingMarkerService.cs @@ -3,7 +3,7 @@ using Microsoft.Extensions.DependencyInjection; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing { /// /// A marker class used to determine if all the routing services were added @@ -12,4 +12,4 @@ namespace Microsoft.AspNetCore.Routing.Internal internal class RoutingMarkerService { } -} \ No newline at end of file +} diff --git a/src/Http/Routing/src/Template/DefaultTemplateBinderFactory.cs b/src/Http/Routing/src/Template/DefaultTemplateBinderFactory.cs new file mode 100644 index 0000000000..86e33e04a3 --- /dev/null +++ b/src/Http/Routing/src/Template/DefaultTemplateBinderFactory.cs @@ -0,0 +1,95 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Routing.Internal; +using Microsoft.AspNetCore.Routing.Patterns; +using Microsoft.Extensions.ObjectPool; + +namespace Microsoft.AspNetCore.Routing.Template +{ + internal sealed class DefaultTemplateBinderFactory : TemplateBinderFactory + { + private readonly ParameterPolicyFactory _policyFactory; +#pragma warning disable CS0618 // Type or member is obsolete + private readonly ObjectPool _pool; +#pragma warning restore CS0618 // Type or member is obsolete + + public DefaultTemplateBinderFactory( + ParameterPolicyFactory policyFactory, +#pragma warning disable CS0618 // Type or member is obsolete + ObjectPool pool) +#pragma warning restore CS0618 // Type or member is obsolete + { + if (policyFactory == null) + { + throw new ArgumentNullException(nameof(policyFactory)); + } + + if (pool == null) + { + throw new ArgumentNullException(nameof(pool)); + } + + _policyFactory = policyFactory; + _pool = pool; + + } + + public override TemplateBinder Create(RouteTemplate template, RouteValueDictionary defaults) + { + if (template == null) + { + throw new ArgumentNullException(nameof(template)); + } + + if (defaults == null) + { + throw new ArgumentNullException(nameof(defaults)); + } + +#pragma warning disable CS0618 // Type or member is obsolete + return new TemplateBinder(UrlEncoder.Default, _pool, template, defaults); +#pragma warning restore CS0618 // Type or member is obsolete + } + + public override TemplateBinder Create(RoutePattern pattern) + { + if (pattern == null) + { + throw new ArgumentNullException(nameof(pattern)); + } + + // Now create the constraints and parameter transformers from the pattern + var policies = new List<(string parameterName, IParameterPolicy policy)>(); + foreach (var kvp in pattern.ParameterPolicies) + { + var parameterName = kvp.Key; + + // It's possible that we don't have an actual route parameter, we need to support that case. + var parameter = pattern.GetParameter(parameterName); + + // Use the first parameter transformer per parameter + var foundTransformer = false; + for (var i = 0; i < kvp.Value.Count; i++) + { + var parameterPolicy = _policyFactory.Create(parameter, kvp.Value[i]); + if (!foundTransformer && parameterPolicy is IOutboundParameterTransformer parameterTransformer) + { + policies.Add((parameterName, parameterTransformer)); + foundTransformer = true; + } + + if (parameterPolicy is IRouteConstraint constraint) + { + policies.Add((parameterName, constraint)); + } + } + } + + return new TemplateBinder(UrlEncoder.Default, _pool, pattern, policies); + } + } +} diff --git a/src/Http/Routing/src/Template/TemplateBinder.cs b/src/Http/Routing/src/Template/TemplateBinder.cs index c78573ab98..efc46f3781 100644 --- a/src/Http/Routing/src/Template/TemplateBinder.cs +++ b/src/Http/Routing/src/Template/TemplateBinder.cs @@ -19,7 +19,9 @@ namespace Microsoft.AspNetCore.Routing.Template public class TemplateBinder { private readonly UrlEncoder _urlEncoder; +#pragma warning disable CS0618 // Type or member is obsolete private readonly ObjectPool _pool; +#pragma warning restore CS0618 // Type or member is obsolete private readonly (string parameterName, IRouteConstraint constraint)[] _constraints; private readonly RouteValueDictionary _defaults; @@ -40,6 +42,9 @@ namespace Microsoft.AspNetCore.Routing.Template /// The . /// The to bind values to. /// The default values for . + [Obsolete( + "This constructor is obsolete and will be marked internal in a furture release. Use the TemplateBinderFactory service " + + "to create TemplateBinder instances.")] public TemplateBinder( UrlEncoder urlEncoder, ObjectPool pool, @@ -60,6 +65,9 @@ namespace Microsoft.AspNetCore.Routing.Template /// /// A list of (, ) pairs to evalute when producing a URI. /// + [Obsolete( + "This constructor is obsolete and will be marked internal in a future release. Use the TemplateBinderFactory service " + + "to create TemplateBinder instances.")] public TemplateBinder( UrlEncoder urlEncoder, ObjectPool pool, @@ -110,6 +118,58 @@ namespace Microsoft.AspNetCore.Routing.Template _slots = AssignSlots(_pattern, _filters); } + internal TemplateBinder( + UrlEncoder urlEncoder, +#pragma warning disable CS0618 // Type or member is obsolete + ObjectPool pool, +#pragma warning restore CS0618 // Type or member is obsolete + RoutePattern pattern, + IEnumerable<(string parameterName, IParameterPolicy policy)> parameterPolicies) + { + if (urlEncoder == null) + { + throw new ArgumentNullException(nameof(urlEncoder)); + } + + if (pool == null) + { + throw new ArgumentNullException(nameof(pool)); + } + + if (pattern == null) + { + throw new ArgumentNullException(nameof(pattern)); + } + + // Parameter policies can be null. + + _urlEncoder = urlEncoder; + _pool = pool; + _pattern = pattern; + _defaults = new RouteValueDictionary(pattern.Defaults); + _requiredKeys = pattern.RequiredValues.Keys.ToArray(); + + // 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. + var filters = new RouteValueDictionary(_defaults); + for (var i = 0; i < pattern.Parameters.Count; i++) + { + filters.Remove(pattern.Parameters[i].Name); + } + _filters = filters.ToArray(); + + _constraints = parameterPolicies + ?.Where(p => p.policy is IRouteConstraint) + .Select(p => (p.parameterName, (IRouteConstraint)p.policy)) + .ToArray() ?? Array.Empty<(string, IRouteConstraint)>(); + _parameterTransformers = parameterPolicies + ?.Where(p => p.policy is IOutboundParameterTransformer) + .Select(p => (p.parameterName, (IOutboundParameterTransformer)p.policy)) + .ToArray() ?? Array.Empty<(string, IOutboundParameterTransformer)>(); + + _slots = AssignSlots(_pattern, _filters); + } + // Step 1: Get the list of values we're going to try to use to match and generate this URI public TemplateValuesResult GetValues(RouteValueDictionary ambientValues, RouteValueDictionary values) { @@ -442,6 +502,7 @@ namespace Microsoft.AspNetCore.Routing.Template } } +#pragma warning disable CS0618 // Type or member is obsolete private bool TryBindValuesCore(UriBuildingContext context, RouteValueDictionary acceptedValues) { // If we have any output parameter transformers, allow them a chance to influence the parameter values @@ -578,6 +639,7 @@ namespace Microsoft.AspNetCore.Routing.Template } return false; } +#pragma warning restore CS0618 // Type or member is obsolete /// /// Compares two objects for equality as parts of a case-insensitive path. diff --git a/src/Http/Routing/src/Template/TemplateBinderFactory.cs b/src/Http/Routing/src/Template/TemplateBinderFactory.cs new file mode 100644 index 0000000000..273b4c4a68 --- /dev/null +++ b/src/Http/Routing/src/Template/TemplateBinderFactory.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Routing.Patterns; + +namespace Microsoft.AspNetCore.Routing.Template +{ + /// + /// A factory used to create instances. + /// + public abstract class TemplateBinderFactory + { + /// + /// Creates a new from the provided and + /// . + /// + /// The route template. + /// A collection of extra default values that do not appear in the route template. + /// A . + public abstract TemplateBinder Create(RouteTemplate template, RouteValueDictionary defaults); + + /// + /// Creates a new from the provided . + /// + /// The . + /// A . + public abstract TemplateBinder Create(RoutePattern pattern); + } +} diff --git a/src/Http/Routing/src/Internal/LinkGenerationDecisionTree.cs b/src/Http/Routing/src/Tree/LinkGenerationDecisionTree.cs similarity index 98% rename from src/Http/Routing/src/Internal/LinkGenerationDecisionTree.cs rename to src/Http/Routing/src/Tree/LinkGenerationDecisionTree.cs index effc1f0b24..8b8315285f 100644 --- a/src/Http/Routing/src/Internal/LinkGenerationDecisionTree.cs +++ b/src/Http/Routing/src/Tree/LinkGenerationDecisionTree.cs @@ -8,13 +8,12 @@ using System.Linq; using System.Text; using Microsoft.AspNetCore.Routing.DecisionTree; using Microsoft.AspNetCore.Routing.Patterns; -using Microsoft.AspNetCore.Routing.Tree; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing.Tree { // A decision tree that matches link generation entries based on route data. [DebuggerDisplay("{DebuggerDisplayString,nq}")] - public class LinkGenerationDecisionTree + internal class LinkGenerationDecisionTree { // Fallback value for cases where the ambient values weren't provided. // diff --git a/src/Http/Routing/src/Internal/OutboundMatchResult.cs b/src/Http/Routing/src/Tree/OutboundMatchResult.cs similarity index 76% rename from src/Http/Routing/src/Internal/OutboundMatchResult.cs rename to src/Http/Routing/src/Tree/OutboundMatchResult.cs index 1b221013ba..ba19555524 100644 --- a/src/Http/Routing/src/Internal/OutboundMatchResult.cs +++ b/src/Http/Routing/src/Tree/OutboundMatchResult.cs @@ -1,11 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNetCore.Routing.Tree; - -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing.Tree { - public readonly struct OutboundMatchResult + internal readonly struct OutboundMatchResult { public OutboundMatchResult(OutboundMatch match, bool isFallbackMatch) { diff --git a/src/Http/Routing/src/Tree/TreeRouteBuilder.cs b/src/Http/Routing/src/Tree/TreeRouteBuilder.cs index a8a11d803b..ba4bdefdfa 100644 --- a/src/Http/Routing/src/Tree/TreeRouteBuilder.cs +++ b/src/Http/Routing/src/Tree/TreeRouteBuilder.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Routing.Internal; @@ -21,7 +20,9 @@ namespace Microsoft.AspNetCore.Routing.Tree private readonly ILogger _logger; private readonly ILogger _constraintLogger; private readonly UrlEncoder _urlEncoder; +#pragma warning disable CS0618 // Type or member is obsolete private readonly ObjectPool _objectPool; +#pragma warning restore CS0618 // Type or member is obsolete private readonly IInlineConstraintResolver _constraintResolver; /// @@ -30,9 +31,12 @@ namespace Microsoft.AspNetCore.Routing.Tree /// The . /// The . /// The . + [Obsolete("This constructor will be marked internal in a future release. Use the service provider to create instances of TreeRouteBuilder.")] public TreeRouteBuilder( ILoggerFactory loggerFactory, +#pragma warning disable CS0618 // Type or member is obsolete ObjectPool objectPool, +#pragma warning restore CS0618 // Type or member is obsolete IInlineConstraintResolver constraintResolver) { if (loggerFactory == null) @@ -240,6 +244,7 @@ namespace Microsoft.AspNetCore.Routing.Tree tree.AddEntry(entry); } +#pragma warning disable CS0618 // Type or member is obsolete return new TreeRouter( trees.Values.OrderBy(tree => tree.Order).ToArray(), OutboundEntries, @@ -248,6 +253,7 @@ namespace Microsoft.AspNetCore.Routing.Tree _logger, _constraintLogger, version); +#pragma warning restore CS0618 // Type or member is obsolete } /// diff --git a/src/Http/Routing/src/Tree/TreeRouter.cs b/src/Http/Routing/src/Tree/TreeRouter.cs index 47fbf3802e..46828b94dd 100644 --- a/src/Http/Routing/src/Tree/TreeRouter.cs +++ b/src/Http/Routing/src/Tree/TreeRouter.cs @@ -40,11 +40,14 @@ namespace Microsoft.AspNetCore.Routing.Tree /// The instance used /// in . /// The version of this route. + [Obsolete("This constructor will be marked obsolete in a future release. Use the TreeRouterBuilder to create instances of TreeRouter.")] public TreeRouter( UrlMatchingTree[] trees, IEnumerable linkGenerationEntries, UrlEncoder urlEncoder, +#pragma warning disable CS0618 // Type or member is obsolete ObjectPool objectPool, +#pragma warning restore CS0618 // Type or member is obsolete ILogger routeLogger, ILogger constraintLogger, int version) diff --git a/src/Http/Routing/src/Internal/UriBuilderContextPooledObjectPolicy.cs b/src/Http/Routing/src/UriBuilderContextPooledObjectPolicy.cs similarity index 62% rename from src/Http/Routing/src/Internal/UriBuilderContextPooledObjectPolicy.cs rename to src/Http/Routing/src/UriBuilderContextPooledObjectPolicy.cs index 953d6a86c4..7ed7021d1f 100644 --- a/src/Http/Routing/src/Internal/UriBuilderContextPooledObjectPolicy.cs +++ b/src/Http/Routing/src/UriBuilderContextPooledObjectPolicy.cs @@ -2,11 +2,13 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Routing.Internal; using Microsoft.Extensions.ObjectPool; -namespace Microsoft.AspNetCore.Routing.Internal +namespace Microsoft.AspNetCore.Routing { - public class UriBuilderContextPooledObjectPolicy : IPooledObjectPolicy +#pragma warning disable CS0618 // Type or member is obsolete + internal class UriBuilderContextPooledObjectPolicy : IPooledObjectPolicy { public UriBuildingContext Create() { @@ -19,4 +21,5 @@ namespace Microsoft.AspNetCore.Routing.Internal return true; } } +#pragma warning restore CS0618 // Type or member is obsolete } diff --git a/src/Http/Routing/test/UnitTests/Internal/UriBuildingContextTest.cs b/src/Http/Routing/test/UnitTests/Internal/UriBuildingContextTest.cs index cfd1531a5d..f9f0be2ab8 100644 --- a/src/Http/Routing/test/UnitTests/Internal/UriBuildingContextTest.cs +++ b/src/Http/Routing/test/UnitTests/Internal/UriBuildingContextTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.Extensions.WebEncoders.Testing; @@ -6,6 +6,7 @@ using Xunit; namespace Microsoft.AspNetCore.Routing.Internal { +#pragma warning disable CS0618 // Type or member is obsolete public class UriBuildingContextTest { [Fact] @@ -16,7 +17,7 @@ namespace Microsoft.AspNetCore.Routing.Internal var value = "a/b b1/c"; var expected = "/UrlEncode[[a/b b1/c]]"; var uriBuilldingContext = new UriBuildingContext(urlTestEncoder); - + // Act uriBuilldingContext.EncodeValue(value, 0, value.Length, encodeSlashes: true); @@ -97,4 +98,5 @@ namespace Microsoft.AspNetCore.Routing.Internal Assert.Equal(expected, uriBuilldingContext.ToPathString().Value); } } +#pragma warning restore CS0618 // Type or member is obsolete } diff --git a/src/Http/Routing/test/UnitTests/LinkGeneratorTestBase.cs b/src/Http/Routing/test/UnitTests/LinkGeneratorTestBase.cs index 202238e5b8..19ded38c8b 100644 --- a/src/Http/Routing/test/UnitTests/LinkGeneratorTestBase.cs +++ b/src/Http/Routing/test/UnitTests/LinkGeneratorTestBase.cs @@ -5,6 +5,7 @@ using System; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Routing.Internal; +using Microsoft.AspNetCore.Routing.Template; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.ObjectPool; @@ -82,8 +83,8 @@ namespace Microsoft.AspNetCore.Routing return new DefaultLinkGenerator( new DefaultParameterPolicyFactory(routeOptions, serviceProvider), + serviceProvider.GetRequiredService(), new CompositeEndpointDataSource(routeOptions.Value.EndpointDataSources), - new DefaultObjectPool(new UriBuilderContextPooledObjectPolicy()), routeOptions, NullLogger.Instance, serviceProvider); diff --git a/src/Http/Routing/test/UnitTests/Matching/TreeRouterMatcherBuilder.cs b/src/Http/Routing/test/UnitTests/Matching/TreeRouterMatcherBuilder.cs index b6346b0f14..5d4e25dfff 100644 --- a/src/Http/Routing/test/UnitTests/Matching/TreeRouterMatcherBuilder.cs +++ b/src/Http/Routing/test/UnitTests/Matching/TreeRouterMatcherBuilder.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; @@ -32,10 +32,12 @@ namespace Microsoft.AspNetCore.Routing.Matching public override Matcher Build() { +#pragma warning disable CS0618 // Type or member is obsolete var builder = new TreeRouteBuilder( NullLoggerFactory.Instance, new DefaultObjectPool(new UriBuilderContextPooledObjectPolicy()), new DefaultInlineConstraintResolver(Options.Create(new RouteOptions()), new TestServiceProvider())); +#pragma warning restore CS0618 // Type or member is obsolete var selector = new DefaultEndpointSelector(); diff --git a/src/Http/Routing/test/UnitTests/RouteTest.cs b/src/Http/Routing/test/UnitTests/RouteTest.cs index 4c0f647caf..db7bce321e 100644 --- a/src/Http/Routing/test/UnitTests/RouteTest.cs +++ b/src/Http/Routing/test/UnitTests/RouteTest.cs @@ -658,6 +658,7 @@ namespace Microsoft.AspNetCore.Routing var expected = "/Home/Index?name=" + UrlEncoder.Default.Encode(nameRouteValue); var services = new ServiceCollection(); services.AddSingleton(NullLoggerFactory.Instance); + services.AddOptions(); services.AddRouting(); // This test encoder should not be used by Routing and should always use the default one. services.AddSingleton(new UrlTestEncoder()); @@ -1520,6 +1521,7 @@ namespace Microsoft.AspNetCore.Routing { var services = new ServiceCollection(); services.AddSingleton(NullLoggerFactory.Instance); + services.AddOptions(); services.AddRouting(); var context = new DefaultHttpContext diff --git a/src/Http/Routing/test/UnitTests/Template/TemplateBinderTests.cs b/src/Http/Routing/test/UnitTests/Template/TemplateBinderTests.cs index f5f497e4b2..0ae7eb7e5b 100644 --- a/src/Http/Routing/test/UnitTests/Template/TemplateBinderTests.cs +++ b/src/Http/Routing/test/UnitTests/Template/TemplateBinderTests.cs @@ -16,6 +16,7 @@ using Xunit; namespace Microsoft.AspNetCore.Routing.Template.Tests { +#pragma warning disable CS0618 // Type or member is obsolete public class TemplateBinderTests { private readonly IInlineConstraintResolver _inlineConstraintResolver = GetInlineConstraintResolver(); @@ -1480,4 +1481,5 @@ namespace Microsoft.AspNetCore.Routing.Template.Tests public Dictionary Parameters { get; private set; } } } +#pragma warning restore CS0618 // Type or member is obsolete } diff --git a/src/Http/Routing/test/UnitTests/Tree/TreeRouteBuilderTest.cs b/src/Http/Routing/test/UnitTests/Tree/TreeRouteBuilderTest.cs index dc9d2c7594..665e11f07e 100644 --- a/src/Http/Routing/test/UnitTests/Tree/TreeRouteBuilderTest.cs +++ b/src/Http/Routing/test/UnitTests/Tree/TreeRouteBuilderTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Text.Encodings.Web; @@ -248,10 +248,12 @@ namespace Microsoft.AspNetCore.Routing.Tree var objectPool = objectPoolProvider.Create(objectPolicy); var constraintResolver = GetInlineConstraintResolver(); +#pragma warning disable CS0618 // Type or member is obsolete var builder = new TreeRouteBuilder( NullLoggerFactory.Instance, objectPool, constraintResolver); +#pragma warning restore CS0618 // Type or member is obsolete return builder; } diff --git a/src/Http/Routing/test/UnitTests/Tree/TreeRouterTest.cs b/src/Http/Routing/test/UnitTests/Tree/TreeRouterTest.cs index b655941c00..d8bd30ae4f 100644 --- a/src/Http/Routing/test/UnitTests/Tree/TreeRouterTest.cs +++ b/src/Http/Routing/test/UnitTests/Tree/TreeRouterTest.cs @@ -23,8 +23,10 @@ namespace Microsoft.AspNetCore.Routing.Tree { private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask; +#pragma warning disable CS0618 // Type or member is obsolete private static ObjectPool Pool = new DefaultObjectPoolProvider().Create( new UriBuilderContextPooledObjectPolicy()); +#pragma warning restore CS0618 // Type or member is obsolete [Theory] [InlineData("template/5", "template/{parameter:int}")] @@ -2073,6 +2075,7 @@ namespace Microsoft.AspNetCore.Routing.Tree return new DefaultInlineConstraintResolver(optionsMock.Object, new TestServiceProvider()); } +#pragma warning disable CS0618 // Type or member is obsolete private static TreeRouteBuilder CreateBuilder() { var objectPoolProvider = new DefaultObjectPoolProvider(); @@ -2086,6 +2089,7 @@ namespace Microsoft.AspNetCore.Routing.Tree constraintResolver); return builder; } +#pragma warning restore CS0618 // Type or member is obsolete private static TreeRouter CreateTreeRouter( string firstTemplate,