diff --git a/Routing.sln b/Routing.sln index 632e7fe0c3..c6de0a91d5 100644 --- a/Routing.sln +++ b/Routing.sln @@ -19,7 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routing.Tests", "test\Microsoft.AspNetCore.Routing.Tests\Microsoft.AspNetCore.Routing.Tests.csproj", "{636D79ED-7B32-487C-BDA5-D2A1AAA97371}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoutingSample.Web", "samples\RoutingSample.Web\RoutingSample.Web.csproj", "{DB94E647-C73A-4F52-A126-AA7544CCF33B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoutingSandbox", "samples\RoutingSample.Web\RoutingSandbox.csproj", "{DB94E647-C73A-4F52-A126-AA7544CCF33B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C430C499-382D-47BD-B351-CF8F89C08CD2}" ProjectSection(SolutionItems) = preProject @@ -55,6 +55,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{6824486A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Swaggatherer", "tools\Swaggatherer\Swaggatherer.csproj", "{B8516771-E850-4724-BEC3-63FC00C2AE57}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebSites", "WebSites", "{8E5E51D4-6B03-4FC6-9F34-6E9FA24702BD}" + ProjectSection(SolutionItems) = preProject + test\WebSites\Directory.Build.props = test\WebSites\Directory.Build.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RoutingWebSite", "test\WebSites\RoutingWebSite\RoutingWebSite.csproj", "{E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -179,6 +186,18 @@ Global {B8516771-E850-4724-BEC3-63FC00C2AE57}.Release|Mixed Platforms.Build.0 = Release|Any CPU {B8516771-E850-4724-BEC3-63FC00C2AE57}.Release|x86.ActiveCfg = Release|Any CPU {B8516771-E850-4724-BEC3-63FC00C2AE57}.Release|x86.Build.0 = Release|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Debug|x86.ActiveCfg = Debug|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Debug|x86.Build.0 = Debug|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Release|Any CPU.Build.0 = Release|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Release|x86.ActiveCfg = Release|Any CPU + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -194,6 +213,8 @@ Global {F3D86714-4E64-41A6-9B36-A47B3683CF5D} = {D5F39F59-5725-4127-82E7-67028D006185} {91F47A60-9A78-4968-B10D-157D9BFAC37F} = {7F5914E2-C63F-4759-898E-462804357C90} {B8516771-E850-4724-BEC3-63FC00C2AE57} = {6824486A-3EFF-45D1-BEE8-8B137639C890} + {8E5E51D4-6B03-4FC6-9F34-6E9FA24702BD} = {95359B4B-4C85-4B44-A75B-0621905C4CF6} + {E91EC5EC-30A8-45EC-9B2F-67E2D6C39D74} = {8E5E51D4-6B03-4FC6-9F34-6E9FA24702BD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {36C8D815-B7F1-479D-894B-E606FB8DECDA} diff --git a/samples/RoutingSample.Web/PrefixRoute.cs b/samples/RoutingSample.Web/PrefixRoute.cs deleted file mode 100644 index 2a68abb183..0000000000 --- a/samples/RoutingSample.Web/PrefixRoute.cs +++ /dev/null @@ -1,62 +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.Threading.Tasks; -using Microsoft.AspNetCore.Routing; - -namespace RoutingSample.Web -{ - public class PrefixRoute : IRouter - { - private readonly IRouteHandler _target; - private readonly string _prefix; - - public PrefixRoute(IRouteHandler target, string prefix) - { - _target = target; - - if (prefix == null) - { - prefix = "/"; - } - else if (prefix.Length > 0 && prefix[0] != '/') - { - // owin.RequestPath starts with a / - prefix = "/" + prefix; - } - - if (prefix.Length > 1 && prefix[prefix.Length - 1] == '/') - { - prefix = prefix.Substring(0, prefix.Length - 1); - } - - _prefix = prefix; - } - - public Task RouteAsync(RouteContext context) - { - var requestPath = context.HttpContext.Request.Path.Value ?? string.Empty; - if (requestPath.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase)) - { - if (requestPath.Length > _prefix.Length) - { - var lastCharacter = requestPath[_prefix.Length]; - if (lastCharacter != '/' && lastCharacter != '#' && lastCharacter != '?') - { - return Task.CompletedTask; - } - } - - context.Handler = _target.GetRequestHandler(context.HttpContext, context.RouteData); - } - - return Task.CompletedTask; - } - - public VirtualPathData GetVirtualPath(VirtualPathContext context) - { - return null; - } - } -} \ No newline at end of file diff --git a/samples/RoutingSample.Web/Program.cs b/samples/RoutingSample.Web/Program.cs index 406e0d591a..35e4e44c01 100644 --- a/samples/RoutingSample.Web/Program.cs +++ b/samples/RoutingSample.Web/Program.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Logging; -namespace RoutingSample.Web +namespace RoutingSandbox { public class Program { diff --git a/samples/RoutingSample.Web/RouteBuilderExtensions.cs b/samples/RoutingSample.Web/RouteBuilderExtensions.cs deleted file mode 100644 index d81735bbc2..0000000000 --- a/samples/RoutingSample.Web/RouteBuilderExtensions.cs +++ /dev/null @@ -1,43 +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.Routing; -using Microsoft.Extensions.DependencyInjection; - -namespace RoutingSample.Web -{ - public static class RouteBuilderExtensions - { - public static IRouteBuilder AddPrefixRoute( - this IRouteBuilder routeBuilder, - string prefix, - IRouteHandler handler) - { - routeBuilder.Routes.Add(new PrefixRoute(handler, prefix)); - return routeBuilder; - } - - public static IRouteBuilder MapLocaleRoute( - this IRouteBuilder routeBuilder, - string locale, - string routeTemplate, - object defaults) - { - var defaultsDictionary = new RouteValueDictionary(defaults); - defaultsDictionary.Add("locale", locale); - - var constraintResolver = routeBuilder.ServiceProvider.GetService(); - - var route = new Route( - target: routeBuilder.DefaultHandler, - routeTemplate: routeTemplate, - defaults: defaultsDictionary, - constraints: null, - dataTokens: null, - inlineConstraintResolver: constraintResolver); - routeBuilder.Routes.Add(route); - - return routeBuilder; - } - } -} \ No newline at end of file diff --git a/samples/RoutingSample.Web/RoutingSample.Web.csproj b/samples/RoutingSample.Web/RoutingSandbox.csproj similarity index 100% rename from samples/RoutingSample.Web/RoutingSample.Web.csproj rename to samples/RoutingSample.Web/RoutingSandbox.csproj diff --git a/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs b/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs index 9a7f058d0f..bfb345cba9 100644 --- a/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs +++ b/samples/RoutingSample.Web/UseEndpointRoutingStartup.cs @@ -14,7 +14,7 @@ using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -namespace RoutingSample.Web +namespace RoutingSandbox { public class UseEndpointRoutingStartup { @@ -23,13 +23,6 @@ namespace RoutingSample.Web public void ConfigureServices(IServiceCollection services) { - services.AddTransient(); - - services.AddRouting(options => - { - options.ConstraintMap.Add("endsWith", typeof(EndsWithStringRouteConstraint)); - }); - var endpointDataSource = new DefaultEndpointDataSource(new[] { new RouteEndpoint((httpContext) => @@ -58,28 +51,6 @@ namespace RoutingSample.Web 0, EndpointMetadataCollection.Empty, "Plaintext"), - new RouteEndpoint((httpContext) => - { - var response = httpContext.Response; - response.StatusCode = 200; - response.ContentType = "text/plain"; - return response.WriteAsync("WithConstraints"); - }, - RoutePatternFactory.Parse("/withconstraints/{id:endsWith(_001)}"), - 0, - EndpointMetadataCollection.Empty, - "withconstraints"), - new RouteEndpoint((httpContext) => - { - var response = httpContext.Response; - response.StatusCode = 200; - response.ContentType = "text/plain"; - return response.WriteAsync("withoptionalconstraints"); - }, - RoutePatternFactory.Parse("/withoptionalconstraints/{id:endsWith(_001)?}"), - 0, - EndpointMetadataCollection.Empty, - "withoptionalconstraints"), new RouteEndpoint((httpContext) => { using (var writer = new StreamWriter(httpContext.Response.Body, Encoding.UTF8, 1024, leaveOpen: true)) @@ -95,40 +66,6 @@ namespace RoutingSample.Web 0, new EndpointMetadataCollection(new HttpMethodMetadata(new[]{ "GET", })), "DFA Graph"), - new RouteEndpoint((httpContext) => - { - var linkGenerator = httpContext.RequestServices.GetRequiredService(); - - var response = httpContext.Response; - response.StatusCode = 200; - response.ContentType = "text/plain"; - return response.WriteAsync( - "Link: " + linkGenerator.GetPathByRouteValues(httpContext, "WithSingleAsteriskCatchAll", new { })); - }, - RoutePatternFactory.Parse("/WithSingleAsteriskCatchAll/{*path}"), - 0, - new EndpointMetadataCollection( - new RouteValuesAddressMetadata( - routeName: "WithSingleAsteriskCatchAll", - requiredValues: new RouteValueDictionary())), - "WithSingleAsteriskCatchAll"), - new RouteEndpoint((httpContext) => - { - var linkGenerator = httpContext.RequestServices.GetRequiredService(); - - var response = httpContext.Response; - response.StatusCode = 200; - response.ContentType = "text/plain"; - return response.WriteAsync( - "Link: " + linkGenerator.GetPathByRouteValues(httpContext, "WithDoubleAsteriskCatchAll", new { })); - }, - RoutePatternFactory.Parse("/WithDoubleAsteriskCatchAll/{**path}"), - 0, - new EndpointMetadataCollection( - new RouteValuesAddressMetadata( - routeName: "WithDoubleAsteriskCatchAll", - requiredValues: new RouteValueDictionary())), - "WithDoubleAsteriskCatchAll"), }); services.TryAddEnumerable(ServiceDescriptor.Singleton(endpointDataSource)); diff --git a/samples/RoutingSample.Web/UseRouterStartup.cs b/samples/RoutingSample.Web/UseRouterStartup.cs index 2d267ef18f..d7ae470989 100644 --- a/samples/RoutingSample.Web/UseRouterStartup.cs +++ b/samples/RoutingSample.Web/UseRouterStartup.cs @@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Constraints; using Microsoft.Extensions.DependencyInjection; -namespace RoutingSample.Web +namespace RoutingSandbox { public class UseRouterStartup { diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 3501751182..c126684d3f 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -8,9 +8,11 @@ $(StandardTestTfms);net461 + + false + + - - diff --git a/test/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests.csproj b/test/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests.csproj index fce9e366fc..c5fa909119 100644 --- a/test/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests.csproj +++ b/test/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests/Microsoft.AspNetCore.Mvc.Routing.Abstractions.Tests.csproj @@ -1,4 +1,4 @@ - + $(StandardTestTfms) @@ -8,4 +8,8 @@ + + + + diff --git a/test/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests.csproj b/test/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests.csproj index 3d127f0370..286e462426 100644 --- a/test/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests.csproj +++ b/test/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests/Microsoft.AspNetCore.Routing.DecisionTree.Sources.Tests.csproj @@ -1,4 +1,4 @@ - + $(StandardTestTfms) diff --git a/test/Microsoft.AspNetCore.Routing.FunctionalTests/EndpointRoutingSampleTest.cs b/test/Microsoft.AspNetCore.Routing.FunctionalTests/EndpointRoutingSampleTest.cs index 6dd2373efe..6f5a978c5f 100644 --- a/test/Microsoft.AspNetCore.Routing.FunctionalTests/EndpointRoutingSampleTest.cs +++ b/test/Microsoft.AspNetCore.Routing.FunctionalTests/EndpointRoutingSampleTest.cs @@ -6,7 +6,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.TestHost; -using RoutingSample.Web; +using RoutingWebSite; using Xunit; namespace Microsoft.AspNetCore.Routing.FunctionalTests diff --git a/test/Microsoft.AspNetCore.Routing.FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj b/test/Microsoft.AspNetCore.Routing.FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj index 9520c32ff5..0fecc56388 100644 --- a/test/Microsoft.AspNetCore.Routing.FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj +++ b/test/Microsoft.AspNetCore.Routing.FunctionalTests/Microsoft.AspNetCore.Routing.FunctionalTests.csproj @@ -6,7 +6,7 @@ - + @@ -17,4 +17,4 @@ - + \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Routing.FunctionalTests/RouterSampleTest.cs b/test/Microsoft.AspNetCore.Routing.FunctionalTests/RouterSampleTest.cs index a925035bc4..315dcc1b68 100644 --- a/test/Microsoft.AspNetCore.Routing.FunctionalTests/RouterSampleTest.cs +++ b/test/Microsoft.AspNetCore.Routing.FunctionalTests/RouterSampleTest.cs @@ -6,7 +6,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.TestHost; -using RoutingSample.Web; +using RoutingWebSite; using Xunit; namespace Microsoft.AspNetCore.Routing.FunctionalTests diff --git a/test/WebSites/Directory.Build.props b/test/WebSites/Directory.Build.props new file mode 100644 index 0000000000..2ff6b1fb54 --- /dev/null +++ b/test/WebSites/Directory.Build.props @@ -0,0 +1,11 @@ + + + + + + netcoreapp2.2 + $(DeveloperBuildTestWebsiteTfms) + netcoreapp2.2 + $(StandardTestWebsiteTfms);net461 + + diff --git a/samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs b/test/WebSites/RoutingWebSite/EndsWithStringRouteConstraint.cs similarity index 97% rename from samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs rename to test/WebSites/RoutingWebSite/EndsWithStringRouteConstraint.cs index 2d1ebecb64..efb8431e2a 100644 --- a/samples/RoutingSample.Web/EndsWithStringRouteConstraint.cs +++ b/test/WebSites/RoutingWebSite/EndsWithStringRouteConstraint.cs @@ -6,7 +6,7 @@ using System.Globalization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -namespace RoutingSample.Web +namespace RoutingWebSite { internal class EndsWithStringRouteConstraint : IRouteConstraint { diff --git a/test/WebSites/RoutingWebSite/Program.cs b/test/WebSites/RoutingWebSite/Program.cs new file mode 100644 index 0000000000..d96af1814f --- /dev/null +++ b/test/WebSites/RoutingWebSite/Program.cs @@ -0,0 +1,72 @@ +// 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.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Logging; + +namespace RoutingWebSite +{ + public class Program + { + public const string EndpointRoutingScenario = "endpointrouting"; + public const string RouterScenario = "router"; + + public static void Main(string[] args) + { + var webHost = GetWebHostBuilder(args).Build(); + webHost.Run(); + } + + // For unit testing + public static IWebHostBuilder GetWebHostBuilder(string[] args) + { + string scenario; + if (args.Length == 0) + { + Console.WriteLine("Choose a sample to run:"); + Console.WriteLine($"1. {EndpointRoutingScenario}"); + Console.WriteLine($"2. {RouterScenario}"); + Console.WriteLine(); + + scenario = Console.ReadLine(); + } + else + { + scenario = args[0]; + } + + Type startupType; + switch (scenario) + { + case "1": + case EndpointRoutingScenario: + startupType = typeof(UseEndpointRoutingStartup); + break; + + case "2": + case RouterScenario: + startupType = typeof(UseRouterStartup); + break; + + default: + Console.WriteLine($"unknown scenario {scenario}"); + Console.WriteLine($"usage: dotnet run -- ({EndpointRoutingScenario}|{RouterScenario})"); + throw new InvalidOperationException(); + + } + + return new WebHostBuilder() + .UseKestrel() + .UseIISIntegration() + .ConfigureLogging(b => + { + b.AddConsole(); + b.SetMinimumLevel(LogLevel.Critical); + }) + .UseContentRoot(Environment.CurrentDirectory) + .UseStartup(startupType); + } + } +} diff --git a/test/WebSites/RoutingWebSite/RoutingWebSite.csproj b/test/WebSites/RoutingWebSite/RoutingWebSite.csproj new file mode 100644 index 0000000000..d462c5fbbc --- /dev/null +++ b/test/WebSites/RoutingWebSite/RoutingWebSite.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.2 + $(TargetFrameworks);net461 + + + + + + + + + + + + + + diff --git a/test/WebSites/RoutingWebSite/UseEndpointRoutingStartup.cs b/test/WebSites/RoutingWebSite/UseEndpointRoutingStartup.cs new file mode 100644 index 0000000000..57bc673573 --- /dev/null +++ b/test/WebSites/RoutingWebSite/UseEndpointRoutingStartup.cs @@ -0,0 +1,148 @@ +// 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.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Internal; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Internal; +using Microsoft.AspNetCore.Routing.Patterns; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace RoutingWebSite +{ + public class UseEndpointRoutingStartup + { + private static readonly byte[] _homePayload = Encoding.UTF8.GetBytes("Endpoint Routing sample endpoints:" + Environment.NewLine + "/plaintext"); + private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); + + public void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + + services.AddRouting(options => + { + options.ConstraintMap.Add("endsWith", typeof(EndsWithStringRouteConstraint)); + }); + + var endpointDataSource = new DefaultEndpointDataSource(new[] + { + new RouteEndpoint((httpContext) => + { + var response = httpContext.Response; + var payloadLength = _homePayload.Length; + response.StatusCode = 200; + response.ContentType = "text/plain"; + response.ContentLength = payloadLength; + return response.Body.WriteAsync(_homePayload, 0, payloadLength); + }, + RoutePatternFactory.Parse("/"), + 0, + EndpointMetadataCollection.Empty, + "Home"), + new RouteEndpoint((httpContext) => + { + var response = httpContext.Response; + var payloadLength = _helloWorldPayload.Length; + response.StatusCode = 200; + response.ContentType = "text/plain"; + response.ContentLength = payloadLength; + return response.Body.WriteAsync(_helloWorldPayload, 0, payloadLength); + }, + RoutePatternFactory.Parse("/plaintext"), + 0, + EndpointMetadataCollection.Empty, + "Plaintext"), + new RouteEndpoint((httpContext) => + { + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync("WithConstraints"); + }, + RoutePatternFactory.Parse("/withconstraints/{id:endsWith(_001)}"), + 0, + EndpointMetadataCollection.Empty, + "withconstraints"), + new RouteEndpoint((httpContext) => + { + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync("withoptionalconstraints"); + }, + RoutePatternFactory.Parse("/withoptionalconstraints/{id:endsWith(_001)?}"), + 0, + EndpointMetadataCollection.Empty, + "withoptionalconstraints"), + new RouteEndpoint((httpContext) => + { + using (var writer = new StreamWriter(httpContext.Response.Body, Encoding.UTF8, 1024, leaveOpen: true)) + { + var graphWriter = httpContext.RequestServices.GetRequiredService(); + var dataSource = httpContext.RequestServices.GetRequiredService(); + graphWriter.Write(dataSource, writer); + } + + return Task.CompletedTask; + }, + RoutePatternFactory.Parse("/graph"), + 0, + new EndpointMetadataCollection(new HttpMethodMetadata(new[]{ "GET", })), + "DFA Graph"), + new RouteEndpoint((httpContext) => + { + var linkGenerator = httpContext.RequestServices.GetRequiredService(); + + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync( + "Link: " + linkGenerator.GetPathByRouteValues(httpContext, "WithSingleAsteriskCatchAll", new { })); + }, + RoutePatternFactory.Parse("/WithSingleAsteriskCatchAll/{*path}"), + 0, + new EndpointMetadataCollection( + new RouteValuesAddressMetadata( + routeName: "WithSingleAsteriskCatchAll", + requiredValues: new RouteValueDictionary())), + "WithSingleAsteriskCatchAll"), + new RouteEndpoint((httpContext) => + { + var linkGenerator = httpContext.RequestServices.GetRequiredService(); + + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync( + "Link: " + linkGenerator.GetPathByRouteValues(httpContext, "WithDoubleAsteriskCatchAll", new { })); + }, + RoutePatternFactory.Parse("/WithDoubleAsteriskCatchAll/{**path}"), + 0, + new EndpointMetadataCollection( + new RouteValuesAddressMetadata( + routeName: "WithDoubleAsteriskCatchAll", + requiredValues: new RouteValueDictionary())), + "WithDoubleAsteriskCatchAll"), + }); + + services.TryAddEnumerable(ServiceDescriptor.Singleton(endpointDataSource)); + } + + public void Configure(IApplicationBuilder app) + { + app.UseEndpointRouting(); + + app.UseStaticFiles(); + + // Imagine some more stuff here... + + app.UseEndpoint(); + } + } +} diff --git a/test/WebSites/RoutingWebSite/UseRouterStartup.cs b/test/WebSites/RoutingWebSite/UseRouterStartup.cs new file mode 100644 index 0000000000..fb27ce550f --- /dev/null +++ b/test/WebSites/RoutingWebSite/UseRouterStartup.cs @@ -0,0 +1,43 @@ +// 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.Text.RegularExpressions; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Constraints; +using Microsoft.Extensions.DependencyInjection; + +namespace RoutingWebSite +{ + public class UseRouterStartup + { + private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10); + + public void ConfigureServices(IServiceCollection services) + { + services.AddRouting(); + } + + public void Configure(IApplicationBuilder app) + { + app.UseRouter(routes => + { + routes.DefaultHandler = new RouteHandler((httpContext) => + { + var request = httpContext.Request; + return httpContext.Response.WriteAsync($"Verb = {request.Method.ToUpperInvariant()} - Path = {request.Path} - Route values - {string.Join(", ", httpContext.GetRouteData().Values)}"); + }); + + routes.MapGet("api/get/{id}", (request, response, routeData) => response.WriteAsync($"API Get {routeData.Values["id"]}")) + .MapMiddlewareRoute("api/middleware", (appBuilder) => appBuilder.Use((httpContext, next) => httpContext.Response.WriteAsync("Middleware!"))) + .MapRoute( + name: "AllVerbs", + template: "api/all/{name}/{lastName?}", + defaults: new { lastName = "Doe" }, + constraints: new { lastName = new RegexRouteConstraint(new Regex("[a-zA-Z]{3}", RegexOptions.CultureInvariant, RegexMatchTimeout)) }); + }); + } + } +}