From bd750ad76daea22de244349e464e91eb58c91c5b Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 28 Sep 2017 22:07:32 -0700 Subject: [PATCH] Making endpoints and addresses easier This makes endpoints and addresses easier to work with by dropping the 'metadata first' approach for the the things that are really at the core of the dispatcher. --- .../HttpMethodEndpointSelector.cs | 16 +-- .../DispatcherSample/HttpMethodMetadata.cs | 23 ---- .../DispatcherSample/IHttpMethodMetadata.cs | 12 -- samples/DispatcherSample/Startup.cs | 23 ++-- ...urce.cs => DefaultDispatcherDataSource.cs} | 4 +- .../DispatcherServiceCollectionExtensions.cs | 2 +- ...ectableEndpoint.cs => ITemplateAddress.cs} | 4 +- .../ITemplateEndpoint.cs | 14 ++ .../SimpleEndpoint.cs | 82 ----------- ...cherValueAddress.cs => TemplateAddress.cs} | 23 ++-- ...Selector.cs => TemplateAddressSelector.cs} | 10 +- .../TemplateEndpoint.cs | 127 ++++++++++++++++++ ...elector.cs => TemplateEndpointSelector.cs} | 4 +- .../Dispatcher/IRouteTemplateMetadata.cs | 14 -- .../Dispatcher/ITreeDispatcherMetadata.cs | 12 -- .../Dispatcher/RouteTemplateMetadata.cs | 33 ----- .../Dispatcher/RouteTemplateUrlGenerator.cs | 22 +-- .../Dispatcher/TreeDispatcher.cs | 8 +- .../ApiAppStartup.cs | 4 +- 19 files changed, 189 insertions(+), 248 deletions(-) delete mode 100644 samples/DispatcherSample/HttpMethodMetadata.cs delete mode 100644 samples/DispatcherSample/IHttpMethodMetadata.cs rename src/Microsoft.AspNetCore.Dispatcher/{SimpleDispatcherDataSource.cs => DefaultDispatcherDataSource.cs} (89%) rename src/Microsoft.AspNetCore.Dispatcher/{IDispatcherValueSelectableEndpoint.cs => ITemplateAddress.cs} (79%) create mode 100644 src/Microsoft.AspNetCore.Dispatcher/ITemplateEndpoint.cs delete mode 100644 src/Microsoft.AspNetCore.Dispatcher/SimpleEndpoint.cs rename src/Microsoft.AspNetCore.Dispatcher/{DispatcherValueAddress.cs => TemplateAddress.cs} (61%) rename src/Microsoft.AspNetCore.Dispatcher/{DispatcherValueAddressSelector.cs => TemplateAddressSelector.cs} (87%) create mode 100644 src/Microsoft.AspNetCore.Dispatcher/TemplateEndpoint.cs rename src/Microsoft.AspNetCore.Dispatcher/{DispatcherValueEndpointSelector.cs => TemplateEndpointSelector.cs} (91%) delete mode 100644 src/Microsoft.AspNetCore.Routing/Dispatcher/IRouteTemplateMetadata.cs delete mode 100644 src/Microsoft.AspNetCore.Routing/Dispatcher/ITreeDispatcherMetadata.cs delete mode 100644 src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateMetadata.cs diff --git a/samples/DispatcherSample/HttpMethodEndpointSelector.cs b/samples/DispatcherSample/HttpMethodEndpointSelector.cs index 16b43234df..594193885f 100644 --- a/samples/DispatcherSample/HttpMethodEndpointSelector.cs +++ b/samples/DispatcherSample/HttpMethodEndpointSelector.cs @@ -23,11 +23,11 @@ namespace DispatcherSample for (var i = context.Endpoints.Count - 1; i >= 0; i--) { var endpoint = context.Endpoints[i]; - IHttpMethodMetadata metadata = null; + ITemplateEndpoint metadata = null; for (var j = endpoint.Metadata.Count - 1; j >= 0; j--) { - metadata = endpoint.Metadata[j] as IHttpMethodMetadata; + metadata = endpoint.Metadata[j] as ITemplateEndpoint; if (metadata != null) { break; @@ -70,17 +70,9 @@ namespace DispatcherSample } } - private bool Matches(IHttpMethodMetadata metadata, string httpMethod) + private bool Matches(ITemplateEndpoint endpoint, string httpMethod) { - for (var i = 0; i < metadata.AllowedMethods.Count; i++) - { - if (string.Equals(metadata.AllowedMethods[i], httpMethod, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; + return string.Equals(endpoint.HttpMethod, httpMethod, StringComparison.OrdinalIgnoreCase); } } } diff --git a/samples/DispatcherSample/HttpMethodMetadata.cs b/samples/DispatcherSample/HttpMethodMetadata.cs deleted file mode 100644 index c2266ead8c..0000000000 --- a/samples/DispatcherSample/HttpMethodMetadata.cs +++ /dev/null @@ -1,23 +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. - -using System; -using System.Collections.Generic; - -namespace DispatcherSample -{ - public class HttpMethodMetadata : IHttpMethodMetadata - { - public HttpMethodMetadata(string httpMethod) - { - if (httpMethod == null) - { - throw new ArgumentNullException(nameof(httpMethod)); - } - - AllowedMethods = new[] { httpMethod, }; - } - - public IReadOnlyList AllowedMethods { get; } - } -} diff --git a/samples/DispatcherSample/IHttpMethodMetadata.cs b/samples/DispatcherSample/IHttpMethodMetadata.cs deleted file mode 100644 index b12731d8df..0000000000 --- a/samples/DispatcherSample/IHttpMethodMetadata.cs +++ /dev/null @@ -1,12 +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. - -using System.Collections.Generic; - -namespace DispatcherSample -{ - public interface IHttpMethodMetadata - { - IReadOnlyList AllowedMethods { get; } - } -} diff --git a/samples/DispatcherSample/Startup.cs b/samples/DispatcherSample/Startup.cs index 0f561a3147..01681344c3 100644 --- a/samples/DispatcherSample/Startup.cs +++ b/samples/DispatcherSample/Startup.cs @@ -1,7 +1,6 @@ // 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.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; @@ -32,27 +31,27 @@ namespace DispatcherSample { Addresses = { - new DispatcherValueAddress(new { controller = "Home", action = "Index", }, new object[]{ new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, "Home:Index()"), - new DispatcherValueAddress(new { controller = "Home", action = "About", }, new object[]{ new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, "Home:About()"), - new DispatcherValueAddress(new { controller = "Admin", action = "Index", }, new object[]{ new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, "Admin:Index()"), - new DispatcherValueAddress(new { controller = "Admin", action = "Users", }, new object[]{ new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, "Admin:GetUsers()/Admin:EditUsers()"), + new TemplateAddress("{controller=Home}/{action=Index}/{id?}", new { controller = "Home", action = "Index", }, "Home:Index()"), + new TemplateAddress("{controller=Home}/{action=Index}/{id?}", new { controller = "Home", action = "About", }, "Home:About()"), + new TemplateAddress("{controller=Home}/{action=Index}/{id?}", new { controller = "Admin", action = "Index", }, "Admin:Index()"), + new TemplateAddress("{controller=Home}/{action=Index}/{id?}", new { controller = "Admin", action = "Users", }, "Admin:GetUsers()/Admin:EditUsers()"), }, Endpoints = { - new SimpleEndpoint(Home_Index, new object[] { new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, new { controller = "Home", action = "Index", }, "Home:Index()"), - new SimpleEndpoint(Home_About, new object[] { new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, new { controller = "Home", action = "About", }, "Home:About()"), - new SimpleEndpoint(Admin_Index, new object[] { new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), }, new { controller = "Admin", action = "Index", }, "Admin:Index()"), - new SimpleEndpoint(Admin_GetUsers, new object[] { new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), new HttpMethodMetadata("GET"), new AuthorizationPolicyMetadata("Admin"), }, new { controller = "Admin", action = "Users", }, "Admin:GetUsers()"), - new SimpleEndpoint(Admin_EditUsers, new object[] { new RouteTemplateMetadata("{controller=Home}/{action=Index}/{id?}"), new HttpMethodMetadata("POST"), new AuthorizationPolicyMetadata("Admin"), }, new { controller = "Admin", action = "Users", }, "Admin:EditUsers()"), + new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Home", action = "Index", }, Home_Index, "Home:Index()"), + new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Home", action = "About", }, Home_About, "Home:About()"), + new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Admin", action = "Index", }, Admin_Index, "Admin:Index()"), + new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Admin", action = "Users", }, "GET", Admin_GetUsers, "Admin:GetUsers()", new AuthorizationPolicyMetadata("Admin")), + new TemplateEndpoint("{controller=Home}/{action=Index}/{id?}", new { controller = "Admin", action = "Users", }, "POST", Admin_EditUsers, "Admin:EditUsers()", new AuthorizationPolicyMetadata("Admin")), }, Selectors = { - new DispatcherValueEndpointSelector(), + new TemplateEndpointSelector(), new HttpMethodEndpointSelector(), } }); - options.HandlerFactories.Add((endpoint) => (endpoint as SimpleEndpoint)?.HandlerFactory); + options.HandlerFactories.Add((endpoint) => (endpoint as TemplateEndpoint)?.HandlerFactory); }); services.AddDispatcher(); diff --git a/src/Microsoft.AspNetCore.Dispatcher/SimpleDispatcherDataSource.cs b/src/Microsoft.AspNetCore.Dispatcher/DefaultDispatcherDataSource.cs similarity index 89% rename from src/Microsoft.AspNetCore.Dispatcher/SimpleDispatcherDataSource.cs rename to src/Microsoft.AspNetCore.Dispatcher/DefaultDispatcherDataSource.cs index 4fa5b6ff5a..026f3b2167 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/SimpleDispatcherDataSource.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/DefaultDispatcherDataSource.cs @@ -7,12 +7,12 @@ using Microsoft.Extensions.Primitives; namespace Microsoft.AspNetCore.Dispatcher { - public class SimpleDispatcherDataSource : DispatcherDataSource + public class DefaultDispatcherDataSource : DispatcherDataSource { private readonly List
_addresses; private readonly List _endpoints; - public SimpleDispatcherDataSource() + public DefaultDispatcherDataSource() { _addresses = new List
(); _endpoints = new List(); diff --git a/src/Microsoft.AspNetCore.Dispatcher/DispatcherServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Dispatcher/DispatcherServiceCollectionExtensions.cs index 23d5a6fdd9..60279ccb11 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/DispatcherServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/DispatcherServiceCollectionExtensions.cs @@ -18,7 +18,7 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/src/Microsoft.AspNetCore.Dispatcher/IDispatcherValueSelectableEndpoint.cs b/src/Microsoft.AspNetCore.Dispatcher/ITemplateAddress.cs similarity index 79% rename from src/Microsoft.AspNetCore.Dispatcher/IDispatcherValueSelectableEndpoint.cs rename to src/Microsoft.AspNetCore.Dispatcher/ITemplateAddress.cs index 61688390ae..dc4697b29e 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/IDispatcherValueSelectableEndpoint.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/ITemplateAddress.cs @@ -3,8 +3,10 @@ namespace Microsoft.AspNetCore.Dispatcher { - public interface IDispatcherValueSelectableEndpoint + public interface ITemplateAddress { + string Template { get; } + DispatcherValueCollection Values { get; } } } diff --git a/src/Microsoft.AspNetCore.Dispatcher/ITemplateEndpoint.cs b/src/Microsoft.AspNetCore.Dispatcher/ITemplateEndpoint.cs new file mode 100644 index 0000000000..06c9c6b091 --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher/ITemplateEndpoint.cs @@ -0,0 +1,14 @@ +// 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.Dispatcher +{ + public interface ITemplateEndpoint + { + string HttpMethod { get; } + + string Template { get; } + + DispatcherValueCollection Values { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Dispatcher/SimpleEndpoint.cs b/src/Microsoft.AspNetCore.Dispatcher/SimpleEndpoint.cs deleted file mode 100644 index 5b81776fc0..0000000000 --- a/src/Microsoft.AspNetCore.Dispatcher/SimpleEndpoint.cs +++ /dev/null @@ -1,82 +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. - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Http; - -namespace Microsoft.AspNetCore.Dispatcher -{ - public class SimpleEndpoint : Endpoint, IDispatcherValueSelectableEndpoint - { - public SimpleEndpoint(RequestDelegate requestDelegate) - : this(requestDelegate, Array.Empty(), null, null) - { - } - - public SimpleEndpoint(Func delegateFactory) - : this(delegateFactory, Array.Empty(), null, null) - { - } - - public SimpleEndpoint(RequestDelegate requestDelegate, IEnumerable metadata) - : this(requestDelegate, metadata, null, null) - { - } - - public SimpleEndpoint(Func delegateFactory, IEnumerable metadata) - : this(delegateFactory, metadata, null, null) - { - } - - public SimpleEndpoint(Func delegateFactory, IEnumerable metadata, object values) - : this(delegateFactory, metadata, null, null) - { - } - - public SimpleEndpoint(RequestDelegate requestDelegate, IEnumerable metadata, object values, string displayName) - { - if (metadata == null) - { - throw new ArgumentNullException(nameof(metadata)); - } - - if (requestDelegate == null) - { - throw new ArgumentNullException(nameof(requestDelegate)); - } - - HandlerFactory = (next) => requestDelegate; - Metadata = metadata.ToArray(); - Values = new DispatcherValueCollection(values); - DisplayName = displayName; - } - - public SimpleEndpoint(Func delegateFactory, IEnumerable metadata, object values, string displayName) - { - if (metadata == null) - { - throw new ArgumentNullException(nameof(metadata)); - } - - if (delegateFactory == null) - { - throw new ArgumentNullException(nameof(delegateFactory)); - } - - HandlerFactory = delegateFactory; - Metadata = metadata.ToArray(); - Values = new DispatcherValueCollection(values); - DisplayName = displayName; - } - - public override string DisplayName { get; } - - public override IReadOnlyList Metadata { get; } - - public Func HandlerFactory { get; } - - public DispatcherValueCollection Values { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Dispatcher/DispatcherValueAddress.cs b/src/Microsoft.AspNetCore.Dispatcher/TemplateAddress.cs similarity index 61% rename from src/Microsoft.AspNetCore.Dispatcher/DispatcherValueAddress.cs rename to src/Microsoft.AspNetCore.Dispatcher/TemplateAddress.cs index 065f56eb7b..606f9997f2 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/DispatcherValueAddress.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/TemplateAddress.cs @@ -7,24 +7,18 @@ using System.Linq; namespace Microsoft.AspNetCore.Dispatcher { - public class DispatcherValueAddress : Address + public class TemplateAddress : Address, ITemplateAddress { - public DispatcherValueAddress(object values) - : this(values, Array.Empty(), null) + public TemplateAddress(string template, object values, params object[] metadata) + : this(template, values, null, metadata) { } - - public DispatcherValueAddress(object values, IEnumerable metadata) - : this(values, metadata, null) + public TemplateAddress(string template, object values, string displayName, params object[] metadata) { - } - - public DispatcherValueAddress(object values, IEnumerable metadata, string displayName) - { - if (values == null) + if (template == null) { - throw new ArgumentNullException(nameof(values)); + throw new ArgumentNullException(nameof(template)); } if (metadata == null) @@ -32,15 +26,18 @@ namespace Microsoft.AspNetCore.Dispatcher throw new ArgumentNullException(nameof(metadata)); } + Template = template; Values = new DispatcherValueCollection(values); - Metadata = metadata.ToArray(); DisplayName = displayName; + Metadata = metadata.ToArray(); } public override string DisplayName { get; } public override IReadOnlyList Metadata { get; } + public string Template { get; } + public DispatcherValueCollection Values { get; } } } diff --git a/src/Microsoft.AspNetCore.Dispatcher/DispatcherValueAddressSelector.cs b/src/Microsoft.AspNetCore.Dispatcher/TemplateAddressSelector.cs similarity index 87% rename from src/Microsoft.AspNetCore.Dispatcher/DispatcherValueAddressSelector.cs rename to src/Microsoft.AspNetCore.Dispatcher/TemplateAddressSelector.cs index d7adebfe5e..efb405f6bf 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/DispatcherValueAddressSelector.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/TemplateAddressSelector.cs @@ -7,11 +7,11 @@ using System.Collections.Generic; namespace Microsoft.AspNetCore.Dispatcher { // This isn't a proposed design, just a placeholder to demonstrate that things are wired up correctly. - public class DispatcherValueAddressSelector + public class TemplateAddressSelector { private readonly AddressTable _addressTable; - public DispatcherValueAddressSelector(AddressTable addressTable) + public TemplateAddressSelector(AddressTable addressTable) { if (addressTable == null) { @@ -37,7 +37,7 @@ namespace Microsoft.AspNetCore.Dispatcher for (var j = 0; j < group.Count; j++) { - var address = group[j] as DispatcherValueAddress; + var address = group[j] as ITemplateAddress; if (address == null) { continue; @@ -45,7 +45,7 @@ namespace Microsoft.AspNetCore.Dispatcher if (IsMatch(address, values)) { - matches.Add(address); + matches.Add(group[j]); } } @@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Dispatcher return null; } - private bool IsMatch(DispatcherValueAddress address, DispatcherValueCollection values) + private bool IsMatch(ITemplateAddress address, DispatcherValueCollection values) { foreach (var kvp in address.Values) { diff --git a/src/Microsoft.AspNetCore.Dispatcher/TemplateEndpoint.cs b/src/Microsoft.AspNetCore.Dispatcher/TemplateEndpoint.cs new file mode 100644 index 0000000000..3618e726c4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher/TemplateEndpoint.cs @@ -0,0 +1,127 @@ +// 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.Linq; +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Dispatcher +{ + public class TemplateEndpoint : Endpoint, ITemplateEndpoint + { + public TemplateEndpoint(string template, RequestDelegate requestDelegate, params object[] metadata) + : this(template, (object)null, (string)null, requestDelegate, null, metadata) + { + } + + public TemplateEndpoint(string template, Func delegateFactory, params object[] metadata) + : this(template, (object)null, (string)null, delegateFactory, null, metadata) + { + } + + public TemplateEndpoint(string template, object values, RequestDelegate requestDelegate, params object[] metadata) + : this(template, values, null, requestDelegate, null, metadata) + { + } + + public TemplateEndpoint(string template, object values, Func delegateFactory, params object[] metadata) + : this(template, values, null, delegateFactory, null, metadata) + { + } + + public TemplateEndpoint(string template, object values, RequestDelegate requestDelegate, string displayName, params object[] metadata) + : this(template, values, null, requestDelegate, displayName, metadata) + { + } + + public TemplateEndpoint(string template, object values, Func delegateFactory, string displayName, params object[] metadata) + : this(template, values, null, delegateFactory, displayName, metadata) + { + } + + public TemplateEndpoint(string template, object values, string httpMethod, RequestDelegate requestDelegate, params object[] metadata) + : this(template, values, httpMethod, requestDelegate, null, metadata) + { + } + + public TemplateEndpoint(string template, object values, string httpMethod, Func delegateFactory, params object[] metadata) + : this(template, values, httpMethod, delegateFactory, null, metadata) + { + } + + public TemplateEndpoint( + string template, + object values, + string httpMethod, + RequestDelegate requestDelegate, + string displayName, + params object[] metadata) + { + if (template == null) + { + throw new ArgumentNullException(nameof(template)); + } + + if (requestDelegate == null) + { + throw new ArgumentNullException(nameof(requestDelegate)); + } + + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + + Template = template; + Values = new DispatcherValueCollection(values); + HttpMethod = httpMethod; + HandlerFactory = (next) => requestDelegate; + DisplayName = displayName; + Metadata = metadata.ToArray(); + } + + public TemplateEndpoint( + string template, + object values, + string httpMethod, + Func delegateFactory, + string displayName, + params object[] metadata) + { + if (template == null) + { + throw new ArgumentNullException(nameof(template)); + } + + if (delegateFactory == null) + { + throw new ArgumentNullException(nameof(delegateFactory)); + } + + if (metadata == null) + { + throw new ArgumentNullException(nameof(metadata)); + } + + Template = template; + Values = new DispatcherValueCollection(values); + HttpMethod = httpMethod; + HandlerFactory = delegateFactory; + DisplayName = displayName; + Metadata = metadata.ToArray(); + } + + public override string DisplayName { get; } + + public string HttpMethod { get; } + + public override IReadOnlyList Metadata { get; } + + public Func HandlerFactory { get; } + + public string Template { get; } + + public DispatcherValueCollection Values { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Dispatcher/DispatcherValueEndpointSelector.cs b/src/Microsoft.AspNetCore.Dispatcher/TemplateEndpointSelector.cs similarity index 91% rename from src/Microsoft.AspNetCore.Dispatcher/DispatcherValueEndpointSelector.cs rename to src/Microsoft.AspNetCore.Dispatcher/TemplateEndpointSelector.cs index a8377321f1..3e2a2d6bb9 100644 --- a/src/Microsoft.AspNetCore.Dispatcher/DispatcherValueEndpointSelector.cs +++ b/src/Microsoft.AspNetCore.Dispatcher/TemplateEndpointSelector.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNetCore.Dispatcher { - public class DispatcherValueEndpointSelector : EndpointSelector + public class TemplateEndpointSelector : EndpointSelector { public override Task SelectAsync(EndpointSelectorContext context) { @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Dispatcher for (var i = context.Endpoints.Count - 1; i >= 0; i--) { - var endpoint = context.Endpoints[i] as IDispatcherValueSelectableEndpoint; + var endpoint = context.Endpoints[i] as ITemplateEndpoint; if (!CompareRouteValues(dispatcherFeature.Values, endpoint.Values)) { context.Endpoints.RemoveAt(i); diff --git a/src/Microsoft.AspNetCore.Routing/Dispatcher/IRouteTemplateMetadata.cs b/src/Microsoft.AspNetCore.Routing/Dispatcher/IRouteTemplateMetadata.cs deleted file mode 100644 index 13f30517b2..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Dispatcher/IRouteTemplateMetadata.cs +++ /dev/null @@ -1,14 +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. - -using Microsoft.AspNetCore.Dispatcher; - -namespace Microsoft.AspNetCore.Routing.Dispatcher -{ - public interface IRouteTemplateMetadata - { - string RouteTemplate { get; } - - DispatcherValueCollection Defaults { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Routing/Dispatcher/ITreeDispatcherMetadata.cs b/src/Microsoft.AspNetCore.Routing/Dispatcher/ITreeDispatcherMetadata.cs deleted file mode 100644 index 27ad992905..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Dispatcher/ITreeDispatcherMetadata.cs +++ /dev/null @@ -1,12 +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.Dispatcher -{ - public interface ITreeDispatcherMetadata - { - int Order { get; } - - string RouteTemplate { get; } - } -} diff --git a/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateMetadata.cs b/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateMetadata.cs deleted file mode 100644 index 8416c422a7..0000000000 --- a/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateMetadata.cs +++ /dev/null @@ -1,33 +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. - -using System; -using Microsoft.AspNetCore.Dispatcher; - -namespace Microsoft.AspNetCore.Routing.Dispatcher -{ - public class RouteTemplateMetadata : IRouteTemplateMetadata, ITreeDispatcherMetadata - { - public RouteTemplateMetadata(string routeTemplate) - : this(routeTemplate, null) - { - } - - public RouteTemplateMetadata(string routeTemplate, object defaults) - { - if (routeTemplate == null) - { - throw new ArgumentNullException(nameof(routeTemplate)); - } - - RouteTemplate = routeTemplate; - Defaults = new DispatcherValueCollection(defaults); - } - - public string RouteTemplate { get; } - - public DispatcherValueCollection Defaults { get; } - - public int Order { get; set; } - } -} diff --git a/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateUrlGenerator.cs b/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateUrlGenerator.cs index 604f3c394a..ac7bf97a56 100644 --- a/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateUrlGenerator.cs +++ b/src/Microsoft.AspNetCore.Routing/Dispatcher/RouteTemplateUrlGenerator.cs @@ -14,11 +14,11 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher // This isn't a proposed design, just a placeholder to demonstrate that things are wired up correctly. public class RouteTemplateUrlGenerator { - private readonly DispatcherValueAddressSelector _addressSelector; + private readonly TemplateAddressSelector _addressSelector; private readonly ObjectPool _pool; private readonly UrlEncoder _urlEncoder; - public RouteTemplateUrlGenerator(DispatcherValueAddressSelector addressSelector, UrlEncoder urlEncoder, ObjectPool pool) + public RouteTemplateUrlGenerator(TemplateAddressSelector addressSelector, UrlEncoder urlEncoder, ObjectPool pool) { _addressSelector = addressSelector; _urlEncoder = urlEncoder; @@ -37,14 +37,13 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher throw new ArgumentNullException(nameof(values)); } - var address = _addressSelector.SelectAddress(new DispatcherValueCollection(values)); + var address = _addressSelector.SelectAddress(new DispatcherValueCollection(values)) as ITemplateAddress; if (address == null) { throw new InvalidOperationException("Can't find address"); } - var (template, defaults) = GetRouteTemplate(address); - var binder = new TemplateBinder(_urlEncoder, _pool, TemplateParser.Parse(template), defaults.AsRouteValueDictionary()); + var binder = new TemplateBinder(_urlEncoder, _pool, TemplateParser.Parse(address.Template), new RouteValueDictionary()); var feature = httpContext.Features.Get(); var result = binder.GetValues(feature.Values.AsRouteValueDictionary(), new RouteValueDictionary(values)); @@ -55,18 +54,5 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher return binder.BindValues(result.AcceptedValues); } - private (string, DispatcherValueCollection) GetRouteTemplate(Address address) - { - for (var i = address.Metadata.Count - 1; i >= 0; i--) - { - var metadata = address.Metadata[i] as IRouteTemplateMetadata; - if (metadata != null) - { - return (metadata.RouteTemplate, metadata.Defaults); - } - } - - return (null, null); - } } } diff --git a/src/Microsoft.AspNetCore.Routing/Dispatcher/TreeDispatcher.cs b/src/Microsoft.AspNetCore.Routing/Dispatcher/TreeDispatcher.cs index 223b7e271e..b2ebd951d0 100644 --- a/src/Microsoft.AspNetCore.Routing/Dispatcher/TreeDispatcher.cs +++ b/src/Microsoft.AspNetCore.Routing/Dispatcher/TreeDispatcher.cs @@ -142,16 +142,16 @@ namespace Microsoft.AspNetCore.Routing.Dispatcher { var endpoint = endpoints[i]; - var metadata = endpoint.Metadata.OfType().LastOrDefault(); - if (metadata == null) + var templateEndpoint = endpoint as ITemplateEndpoint; + if (templateEndpoint == null) { continue; } - if (!groups.TryGetValue(new Key(metadata.Order, metadata.RouteTemplate), out var group)) + if (!groups.TryGetValue(new Key(0, templateEndpoint.Template), out var group)) { group = new List(); - groups.Add(new Key(metadata.Order, metadata.RouteTemplate), group); + groups.Add(new Key(0, templateEndpoint.Template), group); } group.Add(endpoint); diff --git a/test/Microsoft.AspNetCore.Dispatcher.FunctionalTest/ApiAppStartup.cs b/test/Microsoft.AspNetCore.Dispatcher.FunctionalTest/ApiAppStartup.cs index 02e8ea95ab..16db011349 100644 --- a/test/Microsoft.AspNetCore.Dispatcher.FunctionalTest/ApiAppStartup.cs +++ b/test/Microsoft.AspNetCore.Dispatcher.FunctionalTest/ApiAppStartup.cs @@ -58,11 +58,11 @@ namespace Microsoft.AspNetCore.Dispatcher.FunctionalTest { Endpoints = { - new SimpleEndpoint(Products_Get, new object[]{ new RouteTemplateMetadata("api/products"), }), + new TemplateEndpoint("api/products", Products_Get), }, }); - options.HandlerFactories.Add(endpoint => (endpoint as SimpleEndpoint)?.HandlerFactory); + options.HandlerFactories.Add(endpoint => (endpoint as TemplateEndpoint)?.HandlerFactory); } private Task Products_Get(HttpContext httpContext) => httpContext.Response.WriteAsync("Hello, Products_Get");