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 613bd12462..fdeabd02b9 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,12 +23,7 @@ namespace RoutingSample.Web public void ConfigureServices(IServiceCollection services) { - services.AddTransient(); - - services.AddRouting(options => - { - options.ConstraintMap.Add("endsWith", typeof(EndsWithStringRouteConstraint)); - }); + services.AddRouting(); } public void Configure(IApplicationBuilder app) @@ -69,24 +64,6 @@ namespace RoutingSample.Web response.ContentLength = payloadLength; return response.Body.WriteAsync(_plainTextPayload, 0, payloadLength); }); - builder.MapGet( - "/withconstraints/{id:endsWith(_001)}", - (httpContext) => - { - var response = httpContext.Response; - response.StatusCode = 200; - response.ContentType = "text/plain"; - return response.WriteAsync("WithConstraints"); - }); - builder.MapGet( - "/withoptionalconstraints/{id:endsWith(_001)?}", - (httpContext) => - { - var response = httpContext.Response; - response.StatusCode = 200; - response.ContentType = "text/plain"; - return response.WriteAsync("withoptionalconstraints"); - }); builder.MapGet( "/graph", "DFA Graph", @@ -101,32 +78,6 @@ namespace RoutingSample.Web return Task.CompletedTask; }); - builder.MapGet( - "/WithSingleAsteriskCatchAll/{*path}", - (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 { })); - }, - new RouteValuesAddressMetadata(routeName: "WithSingleAsteriskCatchAll", requiredValues: new RouteValueDictionary())); - builder.MapGet( - "/WithDoubleAsteriskCatchAll/{**path}", - (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 { })); - }, - new RouteValuesAddressMetadata(routeName: "WithDoubleAsteriskCatchAll", requiredValues: new RouteValueDictionary())); }); app.UseStaticFiles(); 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 e399c2bad5..6f8241e38b 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/HelloExtension/EndpointRouteBuilderExtensions.cs b/test/WebSites/RoutingWebSite/HelloExtension/EndpointRouteBuilderExtensions.cs new file mode 100644 index 0000000000..fc26b50bf8 --- /dev/null +++ b/test/WebSites/RoutingWebSite/HelloExtension/EndpointRouteBuilderExtensions.cs @@ -0,0 +1,33 @@ +// 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 System.Threading.Tasks; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Matching; +using Microsoft.AspNetCore.Routing.Patterns; + +namespace Microsoft.AspNetCore.Builder +{ + public static class EndpointRouteBuilderExtensions + { + public static IEndpointConventionBuilder MapHello(this IEndpointRouteBuilder builder, string template, string greeter) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + var pipeline = builder.CreateApplicationBuilder() + .UseHello(greeter) + .Build(); + + return builder.Map( + template, + "Hello " + greeter, + pipeline); + } + } +} diff --git a/test/WebSites/RoutingWebSite/HelloExtension/HelloAppBuilderExtensions.cs b/test/WebSites/RoutingWebSite/HelloExtension/HelloAppBuilderExtensions.cs new file mode 100644 index 0000000000..195bec2496 --- /dev/null +++ b/test/WebSites/RoutingWebSite/HelloExtension/HelloAppBuilderExtensions.cs @@ -0,0 +1,25 @@ +// 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.Extensions.Options; +using RoutingWebSite.HelloExtension; + +namespace Microsoft.AspNetCore.Builder +{ + public static class HelloAppBuilderExtensions + { + public static IApplicationBuilder UseHello(this IApplicationBuilder app, string greeter) + { + if (app == null) + { + throw new ArgumentNullException(nameof(app)); + } + + return app.UseMiddleware(Options.Create(new HelloOptions + { + Greeter = greeter + })); + } + } +} diff --git a/test/WebSites/RoutingWebSite/HelloExtension/HelloMiddleware.cs b/test/WebSites/RoutingWebSite/HelloExtension/HelloMiddleware.cs new file mode 100644 index 0000000000..75b2c42749 --- /dev/null +++ b/test/WebSites/RoutingWebSite/HelloExtension/HelloMiddleware.cs @@ -0,0 +1,45 @@ +// 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 System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; + +namespace RoutingWebSite.HelloExtension +{ + public class HelloMiddleware + { + private readonly RequestDelegate _next; + private readonly HelloOptions _helloOptions; + private readonly byte[] _helloPayload; + + public HelloMiddleware(RequestDelegate next, IOptions helloOptions) + { + _next = next; + _helloOptions = helloOptions.Value; + + var payload = new List(); + payload.AddRange(Encoding.UTF8.GetBytes("Hello")); + if (!string.IsNullOrEmpty(_helloOptions.Greeter)) + { + payload.Add((byte)' '); + payload.AddRange(Encoding.UTF8.GetBytes(_helloOptions.Greeter)); + } + _helloPayload = payload.ToArray(); + } + + public Task InvokeAsync(HttpContext context) + { + var response = context.Response; + var payloadLength = _helloPayload.Length; + response.StatusCode = 200; + response.ContentType = "text/plain"; + response.ContentLength = payloadLength; + return response.Body.WriteAsync(_helloPayload, 0, payloadLength); + } + } +} diff --git a/test/WebSites/RoutingWebSite/HelloExtension/HelloOptions.cs b/test/WebSites/RoutingWebSite/HelloExtension/HelloOptions.cs new file mode 100644 index 0000000000..aedad8fb9e --- /dev/null +++ b/test/WebSites/RoutingWebSite/HelloExtension/HelloOptions.cs @@ -0,0 +1,10 @@ +// 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 RoutingWebSite.HelloExtension +{ + public class HelloOptions + { + public string Greeter { get; set; } + } +} 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..a26c16baa2 --- /dev/null +++ b/test/WebSites/RoutingWebSite/UseEndpointRoutingStartup.cs @@ -0,0 +1,123 @@ +// 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.Linq; +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[] _plainTextPayload = Encoding.UTF8.GetBytes("Plain text!"); + + public void ConfigureServices(IServiceCollection services) + { + services.AddTransient(); + + services.AddRouting(options => + { + options.ConstraintMap.Add("endsWith", typeof(EndsWithStringRouteConstraint)); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.UseEndpointRouting(builder => + { + builder.MapHello("/helloworld", "World"); + + builder.MapGet( + "/", + (httpContext) => + { + var dataSource = httpContext.RequestServices.GetRequiredService(); + + var sb = new StringBuilder(); + sb.AppendLine("Endpoints:"); + foreach (var endpoint in dataSource.Endpoints.OfType().OrderBy(e => e.RoutePattern.RawText, StringComparer.OrdinalIgnoreCase)) + { + sb.AppendLine($"- {endpoint.RoutePattern.RawText}"); + } + + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync(sb.ToString()); + }); + builder.MapGet( + "/plaintext", + (httpContext) => + { + var response = httpContext.Response; + var payloadLength = _plainTextPayload.Length; + response.StatusCode = 200; + response.ContentType = "text/plain"; + response.ContentLength = payloadLength; + return response.Body.WriteAsync(_plainTextPayload, 0, payloadLength); + }); + builder.MapGet( + "/withconstraints/{id:endsWith(_001)}", + (httpContext) => + { + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync("WithConstraints"); + }); + builder.MapGet( + "/withoptionalconstraints/{id:endsWith(_001)?}", + (httpContext) => + { + var response = httpContext.Response; + response.StatusCode = 200; + response.ContentType = "text/plain"; + return response.WriteAsync("withoptionalconstraints"); + }); + builder.MapGet( + "/WithSingleAsteriskCatchAll/{*path}", + (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 { })); + }, + new RouteValuesAddressMetadata(routeName: "WithSingleAsteriskCatchAll", requiredValues: new RouteValueDictionary())); + builder.MapGet( + "/WithDoubleAsteriskCatchAll/{**path}", + (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 { })); + }, + new RouteValuesAddressMetadata(routeName: "WithDoubleAsteriskCatchAll", requiredValues: new RouteValueDictionary())); + }); + + 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)) }); + }); + } + } +}