diff --git a/Routing.sln b/Routing.sln index e66c1c9..16a0515 100644 --- a/Routing.sln +++ b/Routing.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.10 +VisualStudioVersion = 15.0.26824.3000 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0E966C37-7334-4D96-AAF6-9F49FBD166E3}" ProjectSection(SolutionItems) = preProject @@ -45,6 +45,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routin EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{D5F39F59-5725-4127-82E7-67028D006185}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Dispatcher", "src\Microsoft.AspNetCore.Dispatcher\Microsoft.AspNetCore.Dispatcher.csproj", "{3FEBCDA2-0381-47B8-A400-4A998D62F86F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Dispatcher.Abstractions", "src\Microsoft.AspNetCore.Dispatcher.Abstractions\Microsoft.AspNetCore.Dispatcher.Abstractions.csproj", "{3153A4B2-BF6B-44EB-8113-F425F07F86E6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Dispatcher.Test", "test\Microsoft.AspNetCore.Dispatcher.Test\Microsoft.AspNetCore.Dispatcher.Test.csproj", "{DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Dispatcher.Abstractions.Test", "test\Microsoft.AspNetCore.Dispatcher.Abstractions.Test\Microsoft.AspNetCore.Dispatcher.Abstractions.Test.csproj", "{14ACBCB4-3B99-425F-A5E2-07E228DEBF63}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DispatcherSample", "samples\DispatcherSample\DispatcherSample.csproj", "{6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Dispatcher.Performance", "benchmarks\Microsoft.AspNetCore.Dispatcher.Performance\Microsoft.AspNetCore.Dispatcher.Performance.csproj", "{30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -145,6 +157,78 @@ Global {F3D86714-4E64-41A6-9B36-A47B3683CF5D}.Release|Mixed Platforms.Build.0 = Release|Any CPU {F3D86714-4E64-41A6-9B36-A47B3683CF5D}.Release|x86.ActiveCfg = Release|Any CPU {F3D86714-4E64-41A6-9B36-A47B3683CF5D}.Release|x86.Build.0 = Release|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Debug|x86.ActiveCfg = Debug|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Debug|x86.Build.0 = Debug|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Release|Any CPU.Build.0 = Release|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Release|x86.ActiveCfg = Release|Any CPU + {3FEBCDA2-0381-47B8-A400-4A998D62F86F}.Release|x86.Build.0 = Release|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Debug|x86.ActiveCfg = Debug|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Debug|x86.Build.0 = Debug|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Release|Any CPU.Build.0 = Release|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Release|x86.ActiveCfg = Release|Any CPU + {3153A4B2-BF6B-44EB-8113-F425F07F86E6}.Release|x86.Build.0 = Release|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Debug|x86.ActiveCfg = Debug|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Debug|x86.Build.0 = Debug|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Release|Any CPU.Build.0 = Release|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Release|x86.ActiveCfg = Release|Any CPU + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92}.Release|x86.Build.0 = Release|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Debug|x86.ActiveCfg = Debug|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Debug|x86.Build.0 = Debug|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Release|Any CPU.Build.0 = Release|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Release|x86.ActiveCfg = Release|Any CPU + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63}.Release|x86.Build.0 = Release|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Debug|x86.ActiveCfg = Debug|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Debug|x86.Build.0 = Debug|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Release|Any CPU.Build.0 = Release|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Release|x86.ActiveCfg = Release|Any CPU + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85}.Release|x86.Build.0 = Release|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Debug|x86.ActiveCfg = Debug|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Debug|x86.Build.0 = Debug|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Release|Any CPU.Build.0 = Release|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Release|x86.ActiveCfg = Release|Any CPU + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -158,8 +242,14 @@ Global {741B0B05-CE96-473B-B962-6B0A347DF79A} = {95359B4B-4C85-4B44-A75B-0621905C4CF6} {5C73140B-41F3-466F-A07B-3614E4D80DF9} = {95359B4B-4C85-4B44-A75B-0621905C4CF6} {F3D86714-4E64-41A6-9B36-A47B3683CF5D} = {D5F39F59-5725-4127-82E7-67028D006185} + {3FEBCDA2-0381-47B8-A400-4A998D62F86F} = {0E966C37-7334-4D96-AAF6-9F49FBD166E3} + {3153A4B2-BF6B-44EB-8113-F425F07F86E6} = {0E966C37-7334-4D96-AAF6-9F49FBD166E3} + {DB2ABDCA-639B-4E0D-B64F-5F6A98A9EC92} = {95359B4B-4C85-4B44-A75B-0621905C4CF6} + {14ACBCB4-3B99-425F-A5E2-07E228DEBF63} = {95359B4B-4C85-4B44-A75B-0621905C4CF6} + {6EBC8AE2-CFF7-46E1-8427-9111FD4F3E85} = {C3ADD55B-B9C7-4061-8AD4-6A70D1AE3B2E} + {30AF355D-E3AB-4FF5-8A59-A253AFEBA26A} = {D5F39F59-5725-4127-82E7-67028D006185} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9F34D81E-5036-4EC8-8012-1EF178A6BBEA} + SolutionGuid = {36C8D815-B7F1-479D-894B-E606FB8DECDA} EndGlobalSection EndGlobal diff --git a/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Configs/CoreConfig.cs b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Configs/CoreConfig.cs new file mode 100644 index 0000000..7be4184 --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Configs/CoreConfig.cs @@ -0,0 +1,31 @@ +// 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 BenchmarkDotNet.Columns; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Engines; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Validators; + +namespace Microsoft.AspNetCore.Dispatcher.Performance +{ + public class CoreConfig : ManualConfig + { + public CoreConfig() + { + Add(JitOptimizationsValidator.FailOnError); + Add(MemoryDiagnoser.Default); + Add(StatisticColumn.OperationsPerSecond); + + Add(Job.Default + .With(BenchmarkDotNet.Environments.Runtime.Core) + .WithRemoveOutliers(false) + .With(new GcMode() { Server = true }) + .With(RunStrategy.Throughput) + .WithLaunchCount(3) + .WithWarmupCount(5) + .WithTargetCount(10)); + } + } +} \ No newline at end of file diff --git a/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/DispatcherBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/DispatcherBenchmark.cs new file mode 100644 index 0000000..3ce51fd --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/DispatcherBenchmark.cs @@ -0,0 +1,116 @@ +// 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.Text.Encodings.Web; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.AspNetCore.Routing.Internal; +using Microsoft.AspNetCore.Routing.Template; +using Microsoft.AspNetCore.Routing.Tree; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.ObjectPool; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Dispatcher.Performance +{ + public class DispatcherBenchmark + { + private const int NumberOfRequestTypes = 3; + private const int Iterations = 100; + + private readonly IRouter _treeRouter; + private readonly RequestEntry[] _requests; + + public DispatcherBenchmark() + { + var handler = new RouteHandler((next) => Task.FromResult(null)); + + var treeBuilder = new TreeRouteBuilder( + NullLoggerFactory.Instance, + UrlEncoder.Default, + new DefaultObjectPool(new UriBuilderContextPooledObjectPolicy(UrlEncoder.Default)), + new DefaultInlineConstraintResolver(new OptionsManager(new OptionsFactory(Enumerable.Empty>(), Enumerable.Empty>())))); + + treeBuilder.MapInbound(handler, TemplateParser.Parse("api/Widgets"), "default", 0); + treeBuilder.MapInbound(handler, TemplateParser.Parse("api/Widgets/{id}"), "default", 0); + treeBuilder.MapInbound(handler, TemplateParser.Parse("api/Widgets/search/{term}"), "default", 0); + treeBuilder.MapInbound(handler, TemplateParser.Parse("admin/users/{id}"), "default", 0); + treeBuilder.MapInbound(handler, TemplateParser.Parse("admin/users/{id}/manage"), "default", 0); + + _treeRouter = treeBuilder.Build(); + + _requests = new RequestEntry[NumberOfRequestTypes]; + + _requests[0].HttpContext = new DefaultHttpContext(); + _requests[0].HttpContext.Request.Path = "/api/Widgets/5"; + _requests[0].IsMatch = true; + _requests[0].Values = new RouteValueDictionary(new { id = 5 }); + + _requests[1].HttpContext = new DefaultHttpContext(); + _requests[1].HttpContext.Request.Path = "/admin/users/17/mAnage"; + _requests[1].IsMatch = true; + _requests[1].Values = new RouteValueDictionary(new { id = 17 }); + + _requests[2].HttpContext = new DefaultHttpContext(); + _requests[2].HttpContext.Request.Path = "/api/Widgets/search/dldldldldld/ddld"; + _requests[2].IsMatch = false; + _requests[2].Values = new RouteValueDictionary(); + } + + [Benchmark(Description = "Attribute Routing", OperationsPerInvoke = Iterations * NumberOfRequestTypes)] + public async Task AttributeRouting() + { + for (var i = 0; i < Iterations; i++) + { + for (var j = 0; j < _requests.Length; j++) + { + var context = new RouteContext(_requests[j].HttpContext); + + await _treeRouter.RouteAsync(context); + + Verify(context, j); + } + } + } + + private void Verify(RouteContext context, int i) + { + if (_requests[i].IsMatch) + { + if (context.Handler == null) + { + throw new InvalidOperationException($"Failed {i}"); + } + + var values = _requests[i].Values; + if (values.Count != context.RouteData.Values.Count) + { + throw new InvalidOperationException($"Failed {i}"); + } + } + else + { + if (context.Handler != null) + { + throw new InvalidOperationException($"Failed {i}"); + } + + if (context.RouteData.Values.Count != 0) + { + throw new InvalidOperationException($"Failed {i}"); + } + } + } + + private struct RequestEntry + { + public HttpContext HttpContext; + public bool IsMatch; + public RouteValueDictionary Values; + } + } +} diff --git a/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Microsoft.AspNetCore.Dispatcher.Performance.csproj b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Microsoft.AspNetCore.Dispatcher.Performance.csproj new file mode 100644 index 0000000..627e86f --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Microsoft.AspNetCore.Dispatcher.Performance.csproj @@ -0,0 +1,24 @@ + + + + netcoreapp2.0;net461 + netcoreapp2.0 + Exe + true + true + false + + + + + + + + + + + + + + + diff --git a/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Program.cs b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Program.cs new file mode 100644 index 0000000..29cf919 --- /dev/null +++ b/benchmarks/Microsoft.AspNetCore.Dispatcher.Performance/Program.cs @@ -0,0 +1,16 @@ +// 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.Reflection; +using BenchmarkDotNet.Running; + +namespace Microsoft.AspNetCore.Dispatcher.Performance +{ + public class Program + { + public static void Main(string[] args) + { + BenchmarkSwitcher.FromAssembly(typeof(Program).GetTypeInfo().Assembly).Run(args); + } + } +} diff --git a/benchmarks/Microsoft.AspNetCore.Routing.Performance/RoutingBenchmark.cs b/benchmarks/Microsoft.AspNetCore.Routing.Performance/RoutingBenchmark.cs index 303fb5e..76cca85 100644 --- a/benchmarks/Microsoft.AspNetCore.Routing.Performance/RoutingBenchmark.cs +++ b/benchmarks/Microsoft.AspNetCore.Routing.Performance/RoutingBenchmark.cs @@ -7,15 +7,12 @@ using System.Text.Encodings.Web; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Template; using Microsoft.AspNetCore.Routing.Tree; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.Options; -using System.Diagnostics; namespace Microsoft.AspNetCore.Routing.Performance { @@ -30,7 +27,7 @@ namespace Microsoft.AspNetCore.Routing.Performance public RoutingBenchmark() { var handler = new RouteHandler((next) => Task.FromResult(null)); - + var treeBuilder = new TreeRouteBuilder( NullLoggerFactory.Instance, UrlEncoder.Default, diff --git a/samples/DispatcherSample/DispatcherEndpoint.cs b/samples/DispatcherSample/DispatcherEndpoint.cs new file mode 100644 index 0000000..b58156e --- /dev/null +++ b/samples/DispatcherSample/DispatcherEndpoint.cs @@ -0,0 +1,17 @@ +// 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 DispatcherSample +{ + public class DispatcherEndpoint : Endpoint + { + public DispatcherEndpoint(string displayName) + { + DisplayName = displayName; + } + + public override string DisplayName { get; } + } +} diff --git a/samples/DispatcherSample/DispatcherFeature.cs b/samples/DispatcherSample/DispatcherFeature.cs new file mode 100644 index 0000000..69dd17a --- /dev/null +++ b/samples/DispatcherSample/DispatcherFeature.cs @@ -0,0 +1,40 @@ +// 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; +using Microsoft.AspNetCore.Http; + +namespace DispatcherSample +{ + public class DispatcherFeature : IDispatcherFeature + { + private Endpoint _endpoint; + private RequestDelegate _next; + + public Endpoint Endpoint + { + get + { + return _endpoint; + } + + set + { + _endpoint = value; + } + } + + public RequestDelegate RequestDelegate + { + get + { + return _next; + } + + set + { + _next = value; + } + } + } +} diff --git a/samples/DispatcherSample/DispatcherSample.csproj b/samples/DispatcherSample/DispatcherSample.csproj new file mode 100644 index 0000000..129261e --- /dev/null +++ b/samples/DispatcherSample/DispatcherSample.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0;net461 + netcoreapp2.0 + + + + + + + + + + + + + + + diff --git a/samples/DispatcherSample/Program.cs b/samples/DispatcherSample/Program.cs new file mode 100644 index 0000000..6ff193b --- /dev/null +++ b/samples/DispatcherSample/Program.cs @@ -0,0 +1,21 @@ +// 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.Hosting; + +namespace DispatcherSample +{ + public class Program + { + public static void Main(string[] args) + { + var host = new WebHostBuilder() + .UseIISIntegration() + .UseKestrel() + .UseStartup() + .Build(); + + host.Run(); + } + } +} diff --git a/samples/DispatcherSample/Startup.cs b/samples/DispatcherSample/Startup.cs new file mode 100644 index 0000000..ac14d28 --- /dev/null +++ b/samples/DispatcherSample/Startup.cs @@ -0,0 +1,80 @@ +// 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 Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Dispatcher; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; + +namespace DispatcherSample +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + } + + public void Configure(IApplicationBuilder app, IHostingEnvironment env) + { + app.Use(async (context, next) => + { + await context.Response.WriteAsync("

Middleware 1

"); + await next.Invoke(); + }); + + var dictionary = new Dictionary + { + { + "/example", + new DispatcherFeature + { + Endpoint = new DispatcherEndpoint("example"), + RequestDelegate = async (context) => + { + await context.Response.WriteAsync("Hello from the example!"); + } + } + }, + { + "/example2", + new DispatcherFeature + { + Endpoint = new DispatcherEndpoint("example2"), + RequestDelegate = async (context) => + { + await context.Response.WriteAsync("Hello from the second example!"); + } + } + }, + }; + + app.Use(async (context, next) => + { + if (dictionary.TryGetValue(context.Request.Path, out var value)) + { + var dispatcherFeature = new DispatcherFeature(); + dispatcherFeature.Endpoint = value.Endpoint; + dispatcherFeature.RequestDelegate = value.RequestDelegate; + context.Features.Set(dispatcherFeature); + await context.Response.WriteAsync("

Dispatch

"); + await next.Invoke(); + } + }); + + app.Use(async (context, next) => + { + await context.Response.WriteAsync("

Middleware 2

"); + await next.Invoke(); + }); + + app.Run(async (context) => + { + var feature = context.Features.Get(); + await feature.RequestDelegate(context); + }); + } + } +} diff --git a/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Address.cs b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Address.cs new file mode 100644 index 0000000..a9008a6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Address.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 Microsoft.AspNetCore.Dispatcher +{ + public abstract class Address + { + public abstract string DisplayName { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Endpoint.cs b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Endpoint.cs new file mode 100644 index 0000000..a2f9092 --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Endpoint.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 Microsoft.AspNetCore.Dispatcher +{ + public abstract class Endpoint + { + public abstract string DisplayName { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Dispatcher.Abstractions/IDispatcherFeature.cs b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/IDispatcherFeature.cs new file mode 100644 index 0000000..85e2645 --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/IDispatcherFeature.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. + +using Microsoft.AspNetCore.Http; + +namespace Microsoft.AspNetCore.Dispatcher +{ + public interface IDispatcherFeature + { + Endpoint Endpoint { get; } + + RequestDelegate RequestDelegate { get; } + } +} diff --git a/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Microsoft.AspNetCore.Dispatcher.Abstractions.csproj b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Microsoft.AspNetCore.Dispatcher.Abstractions.csproj new file mode 100644 index 0000000..d0caf33 --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher.Abstractions/Microsoft.AspNetCore.Dispatcher.Abstractions.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + $(NoWarn);CS1591 + true + aspnetcore;routing + + + + + + + diff --git a/src/Microsoft.AspNetCore.Dispatcher/Microsoft.AspNetCore.Dispatcher.csproj b/src/Microsoft.AspNetCore.Dispatcher/Microsoft.AspNetCore.Dispatcher.csproj new file mode 100644 index 0000000..388054b --- /dev/null +++ b/src/Microsoft.AspNetCore.Dispatcher/Microsoft.AspNetCore.Dispatcher.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + $(NoWarn);CS1591 + true + aspnetcore;routing + + + + + + + + + + + diff --git a/test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test/DispatcherAbstractionsTest.cs b/test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test/DispatcherAbstractionsTest.cs new file mode 100644 index 0000000..8d76aa5 --- /dev/null +++ b/test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test/DispatcherAbstractionsTest.cs @@ -0,0 +1,16 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.Dispatcher.Abstractions.Test +{ + public class DispatcherAbstractionsTest + { + [Fact] + public void Test() + { + + } + } +} diff --git a/test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test.csproj b/test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test.csproj new file mode 100644 index 0000000..5b4d0e0 --- /dev/null +++ b/test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test/Microsoft.AspNetCore.Dispatcher.Abstractions.Test.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp2.0;net461 + netcoreapp2.0 + + + + + + + diff --git a/test/Microsoft.AspNetCore.Dispatcher.Test/DispatcherTest.cs b/test/Microsoft.AspNetCore.Dispatcher.Test/DispatcherTest.cs new file mode 100644 index 0000000..3c0b79e --- /dev/null +++ b/test/Microsoft.AspNetCore.Dispatcher.Test/DispatcherTest.cs @@ -0,0 +1,16 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.Dispatcher.Abstractions.Test +{ + public class DispatcherTest + { + [Fact] + public void Test() + { + + } + } +} diff --git a/test/Microsoft.AspNetCore.Dispatcher.Test/Microsoft.AspNetCore.Dispatcher.Test.csproj b/test/Microsoft.AspNetCore.Dispatcher.Test/Microsoft.AspNetCore.Dispatcher.Test.csproj new file mode 100644 index 0000000..6f4ba1c --- /dev/null +++ b/test/Microsoft.AspNetCore.Dispatcher.Test/Microsoft.AspNetCore.Dispatcher.Test.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp2.0;net461 + netcoreapp2.0 + + + + + + +