Merge pull request #650 from aspnet/release/2.2

automerge release/2.2 -> master
This commit is contained in:
Ryan Nowak 2018-07-22 19:38:53 -07:00 committed by GitHub
commit 184dc270f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 316 additions and 347 deletions

View File

@ -1,4 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 12.00 
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.27106.3000 VisualStudioVersion = 15.0.27106.3000
MinimumVisualStudioVersion = 15.0.26730.03 MinimumVisualStudioVersion = 15.0.26730.03
@ -44,15 +45,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6DC6B416
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routing.Performance", "benchmarks\Microsoft.AspNetCore.Routing.Performance\Microsoft.AspNetCore.Routing.Performance.csproj", "{F3D86714-4E64-41A6-9B36-A47B3683CF5D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Routing.Performance", "benchmarks\Microsoft.AspNetCore.Routing.Performance\Microsoft.AspNetCore.Routing.Performance.csproj", "{F3D86714-4E64-41A6-9B36-A47B3683CF5D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DispatcherSample.Web", "samples\DispatcherSample.Web\DispatcherSample.Web.csproj", "{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{D5F39F59-5725-4127-82E7-67028D006185}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{D5F39F59-5725-4127-82E7-67028D006185}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{7F5914E2-C63F-4759-898E-462804357C90}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{7F5914E2-C63F-4759-898E-462804357C90}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "benchmarkapps\Benchmarks\Benchmarks.csproj", "{91F47A60-9A78-4968-B10D-157D9BFAC37F}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Benchmarks", "benchmarkapps\Benchmarks\Benchmarks.csproj", "{91F47A60-9A78-4968-B10D-157D9BFAC37F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Swaggatherer", "benchmarks\Swaggatherer\Swaggatherer.csproj", "{990ECDEE-49DE-45E3-B0D9-DDEB9CFF6A9D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Swaggatherer", "benchmarks\Swaggatherer\Swaggatherer.csproj", "{990ECDEE-49DE-45E3-B0D9-DDEB9CFF6A9D}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -154,18 +153,6 @@ Global
{F3D86714-4E64-41A6-9B36-A47B3683CF5D}.Release|Mixed Platforms.Build.0 = Release|Any CPU {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.ActiveCfg = Release|Any CPU
{F3D86714-4E64-41A6-9B36-A47B3683CF5D}.Release|x86.Build.0 = Release|Any CPU {F3D86714-4E64-41A6-9B36-A47B3683CF5D}.Release|x86.Build.0 = Release|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Debug|x86.ActiveCfg = Debug|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Debug|x86.Build.0 = Debug|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Release|Any CPU.Build.0 = Release|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Release|x86.ActiveCfg = Release|Any CPU
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5}.Release|x86.Build.0 = Release|Any CPU
{91F47A60-9A78-4968-B10D-157D9BFAC37F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {91F47A60-9A78-4968-B10D-157D9BFAC37F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91F47A60-9A78-4968-B10D-157D9BFAC37F}.Debug|Any CPU.Build.0 = Debug|Any CPU {91F47A60-9A78-4968-B10D-157D9BFAC37F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91F47A60-9A78-4968-B10D-157D9BFAC37F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU {91F47A60-9A78-4968-B10D-157D9BFAC37F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -203,7 +190,6 @@ Global
{741B0B05-CE96-473B-B962-6B0A347DF79A} = {95359B4B-4C85-4B44-A75B-0621905C4CF6} {741B0B05-CE96-473B-B962-6B0A347DF79A} = {95359B4B-4C85-4B44-A75B-0621905C4CF6}
{5C73140B-41F3-466F-A07B-3614E4D80DF9} = {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} {F3D86714-4E64-41A6-9B36-A47B3683CF5D} = {D5F39F59-5725-4127-82E7-67028D006185}
{4EBE7A6F-3183-4A7D-B3D7-A6A9EC3867A5} = {C3ADD55B-B9C7-4061-8AD4-6A70D1AE3B2E}
{91F47A60-9A78-4968-B10D-157D9BFAC37F} = {7F5914E2-C63F-4759-898E-462804357C90} {91F47A60-9A78-4968-B10D-157D9BFAC37F} = {7F5914E2-C63F-4759-898E-462804357C90}
{990ECDEE-49DE-45E3-B0D9-DDEB9CFF6A9D} = {D5F39F59-5725-4127-82E7-67028D006185} {990ECDEE-49DE-45E3-B0D9-DDEB9CFF6A9D} = {D5F39F59-5725-4127-82E7-67028D006185}
EndGlobalSection EndGlobalSection

View File

@ -29,22 +29,22 @@ namespace Benchmarks
.UseKestrel(); .UseKestrel();
var scenario = config["scenarios"]?.ToLower(); var scenario = config["scenarios"]?.ToLower();
if (scenario == "plaintextdispatcher") if (scenario == "plaintextdispatcher" || scenario == "plaintextglobalrouting")
{ {
webHostBuilder.UseStartup<StartupUsingDispatcher>(); webHostBuilder.UseStartup<StartupUsingGlobalRouting>();
// for testing // for testing
webHostBuilder.UseSetting("Startup", nameof(StartupUsingDispatcher)); webHostBuilder.UseSetting("Startup", nameof(StartupUsingGlobalRouting));
} }
else if (scenario == "plaintextrouting") else if (scenario == "plaintextrouting" || scenario == "plaintextrouter")
{ {
webHostBuilder.UseStartup<StartupUsingRouting>(); webHostBuilder.UseStartup<StartupUsingRouter>();
// for testing // for testing
webHostBuilder.UseSetting("Startup", nameof(StartupUsingRouting)); webHostBuilder.UseSetting("Startup", nameof(StartupUsingRouter));
} }
else else
{ {
throw new InvalidOperationException( throw new InvalidOperationException(
$"Invalid scenario '{scenario}'. Allowed scenarios are PlaintextDispatcher and PlaintextRouting"); $"Invalid scenario '{scenario}'. Allowed scenarios are PlaintextGlobalRouting and PlaintextRouter");
} }
return webHostBuilder; return webHostBuilder;

View File

@ -10,7 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace Benchmarks namespace Benchmarks
{ {
public class StartupUsingDispatcher public class StartupUsingGlobalRouting
{ {
private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
@ -18,7 +18,7 @@ namespace Benchmarks
{ {
services.AddRouting(); services.AddRouting();
services.AddDispatcher(options => services.Configure<EndpointOptions>(options =>
{ {
options.DataSources.Add(new DefaultEndpointDataSource(new[] options.DataSources.Add(new DefaultEndpointDataSource(new[]
{ {
@ -43,7 +43,7 @@ namespace Benchmarks
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app)
{ {
app.UseDispatcher(); app.UseGlobalRouting();
app.UseEndpoint(); app.UseEndpoint();
} }

View File

@ -8,7 +8,7 @@ using System.Text;
namespace Benchmarks namespace Benchmarks
{ {
public class StartupUsingRouting public class StartupUsingRouter
{ {
private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");

View File

@ -16,7 +16,13 @@
"PlaintextRouting": { "PlaintextRouting": {
"Path": "/plaintext" "Path": "/plaintext"
}, },
"PlaintextRouter": {
"Path": "/plaintext"
},
"PlaintextDispatcher": { "PlaintextDispatcher": {
"Path": "/plaintext" "Path": "/plaintext"
},
"PlaintextGlobalRouting": {
"Path": "/plaintext"
} }
} }

View File

@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
var sample = _samples[i]; var sample = _samples[i];
var httpContext = Requests[sample]; var httpContext = Requests[sample];
// This is required to make the legacy router implementation work with dispatcher. // This is required to make the legacy router implementation work with global routing.
httpContext.Features.Set<IEndpointFeature>(feature); httpContext.Features.Set<IEndpointFeature>(feature);
await _tree.MatchAsync(httpContext, feature); await _tree.MatchAsync(httpContext, feature);

View File

@ -25,7 +25,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
services.AddLogging(); services.AddLogging();
services.AddOptions(); services.AddOptions();
services.AddRouting(); services.AddRouting();
services.AddDispatcher();
return services.BuildServiceProvider(); return services.BuildServiceProvider();
} }

View File

@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
{ {
var httpContext = Requests[i]; var httpContext = Requests[i];
// This is required to make the legacy router implementation work with dispatcher. // This is required to make the legacy router implementation work with global routing.
httpContext.Features.Set<IEndpointFeature>(feature); httpContext.Features.Set<IEndpointFeature>(feature);
await _tree.MatchAsync(httpContext, feature); await _tree.MatchAsync(httpContext, feature);

View File

@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
var httpContext = Requests[0]; var httpContext = Requests[0];
// This is required to make the legacy router implementation work with dispatcher. // This is required to make the legacy router implementation work with global routing.
httpContext.Features.Set<IEndpointFeature>(feature); httpContext.Features.Set<IEndpointFeature>(feature);
await _tree.MatchAsync(httpContext, feature); await _tree.MatchAsync(httpContext, feature);
@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
var feature = _feature; var feature = _feature;
var httpContext = Requests[0]; var httpContext = Requests[0];
// This is required to make the legacy router implementation work with dispatcher. // This is required to make the legacy router implementation work with global routing.
httpContext.Features.Set<IEndpointFeature>(feature); httpContext.Features.Set<IEndpointFeature>(feature);
await _route.MatchAsync(httpContext, feature); await _route.MatchAsync(httpContext, feature);

View File

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.2</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);net461</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Routing\Microsoft.AspNetCore.Routing.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -1,26 +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.Builder;
using Microsoft.AspNetCore.Hosting;
namespace DispatcherSample.Web
{
public class Program
{
public static void Main(string[] args)
{
var webHost = GetWebHostBuilder().Build();
webHost.Run();
}
// For unit testing
public static IWebHostBuilder GetWebHostBuilder()
{
return new WebHostBuilder()
.UseKestrel()
.UseIISIntegration()
.UseStartup<Startup>();
}
}
}

View File

@ -6,7 +6,7 @@ using System.Globalization;
using Microsoft.AspNetCore.Routing.Matchers; using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace DispatcherSample.Web namespace RoutingSample.Web
{ {
internal class EndsWithStringMatchProcessor : MatchProcessorBase internal class EndsWithStringMatchProcessor : MatchProcessorBase
{ {

View File

@ -44,14 +44,14 @@ namespace RoutingSample.Web
var lastCharacter = requestPath[_prefix.Length]; var lastCharacter = requestPath[_prefix.Length];
if (lastCharacter != '/' && lastCharacter != '#' && lastCharacter != '?') if (lastCharacter != '/' && lastCharacter != '#' && lastCharacter != '?')
{ {
return Task.FromResult(0); return Task.CompletedTask;
} }
} }
context.Handler = _target.GetRequestHandler(context.HttpContext, context.RouteData); context.Handler = _target.GetRequestHandler(context.HttpContext, context.RouteData);
} }
return Task.FromResult(0); return Task.CompletedTask;
} }
public VirtualPathData GetVirtualPath(VirtualPathContext context) public VirtualPathData GetVirtualPath(VirtualPathContext context)

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // 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.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
@ -8,19 +9,57 @@ namespace RoutingSample.Web
{ {
public class Program public class Program
{ {
public static readonly string GlobalRoutingScenario = "globalrouting";
public static readonly string RouterScenario = "router";
public static void Main(string[] args) public static void Main(string[] args)
{ {
var webHost = GetWebHostBuilder().Build(); var webHost = GetWebHostBuilder(args).Build();
webHost.Run(); webHost.Run();
} }
// For unit testing // For unit testing
public static IWebHostBuilder GetWebHostBuilder() public static IWebHostBuilder GetWebHostBuilder(string[] args)
{ {
string scenario;
if (args.Length == 0)
{
Console.WriteLine("Choose a sample to run:");
Console.WriteLine($"1. {GlobalRoutingScenario}");
Console.WriteLine($"2. {RouterScenario}");
Console.WriteLine();
scenario = Console.ReadLine();
}
else
{
scenario = args[0];
}
Type startupType;
switch (scenario)
{
case "1":
case "globalrouting":
startupType = typeof(UseGlobalRoutingStartup);
break;
case "2":
case "router":
startupType = typeof(UseRouterStartup);
break;
default:
Console.WriteLine($"unknown scenario {scenario}");
Console.WriteLine($"usage: dotnet run -- ({GlobalRoutingScenario}|{RouterScenario})");
throw new InvalidOperationException();
}
return new WebHostBuilder() return new WebHostBuilder()
.UseKestrel() .UseKestrel()
.UseIISIntegration() .UseIISIntegration()
.UseStartup<Startup>(); .UseStartup(startupType);
} }
} }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Text; using System.Text;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -11,11 +10,11 @@ using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.AspNetCore.Routing.Patterns; using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace DispatcherSample.Web namespace RoutingSample.Web
{ {
public class Startup public class UseGlobalRoutingStartup
{ {
private static readonly byte[] _homePayload = Encoding.UTF8.GetBytes("Dispatcher sample endpoints:" + Environment.NewLine + "/plaintext"); private static readonly byte[] _homePayload = Encoding.UTF8.GetBytes("Global Routing sample endpoints:" + Environment.NewLine + "/plaintext");
private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!"); private static readonly byte[] _helloWorldPayload = Encoding.UTF8.GetBytes("Hello, World!");
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
@ -26,11 +25,11 @@ namespace DispatcherSample.Web
{ {
options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor)); options.ConstraintMap.Add("endsWith", typeof(EndsWithStringMatchProcessor));
}); });
services.AddDispatcher(options => services.Configure<EndpointOptions>(options =>
{ {
options.DataSources.Add(new DefaultEndpointDataSource(new[] options.DataSources.Add(new DefaultEndpointDataSource(new[]
{ {
new MatcherEndpoint((next) => (httpContext) => new MatcherEndpoint((next) => (httpContext) =>
{ {
var response = httpContext.Response; var response = httpContext.Response;
@ -83,13 +82,13 @@ namespace DispatcherSample.Web
0, 0,
EndpointMetadataCollection.Empty, EndpointMetadataCollection.Empty,
"withoptionalconstraints"), "withoptionalconstraints"),
})); }));
}); });
} }
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app)
{ {
app.UseDispatcher(); app.UseGlobalRouting();
// Imagine some more stuff here... // Imagine some more stuff here...

View File

@ -11,7 +11,7 @@ using Microsoft.Extensions.DependencyInjection;
namespace RoutingSample.Web namespace RoutingSample.Web
{ {
public class Startup public class UseRouterStartup
{ {
private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10); private static readonly TimeSpan RegexMatchTimeout = TimeSpan.FromSeconds(10);

View File

@ -1,52 +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.Routing;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Builder
{
public static class DispatcherApplicationBuilderExtensions
{
private const string DispatcherRegisteredKey = "__DispatcherMiddlewareRegistered";
public static IApplicationBuilder UseDispatcher(this IApplicationBuilder builder)
{
VerifyDispatcherIsRegistered(builder);
builder.Properties[DispatcherRegisteredKey] = true;
return builder.UseMiddleware<DispatcherMiddleware>();
}
public static IApplicationBuilder UseEndpoint(this IApplicationBuilder builder)
{
VerifyDispatcherIsRegistered(builder);
if (!builder.Properties.TryGetValue(DispatcherRegisteredKey, out _))
{
var message = $"{nameof(DispatcherMiddleware)} must be added to the request execution pipeline before {nameof(EndpointMiddleware)}. " +
$"Please add {nameof(DispatcherMiddleware)} by calling '{nameof(IApplicationBuilder)}.{nameof(UseDispatcher)}' inside the call to 'Configure(...)' in the application startup code.";
throw new InvalidOperationException(message);
}
return builder.UseMiddleware<EndpointMiddleware>();
}
private static void VerifyDispatcherIsRegistered(IApplicationBuilder app)
{
// Verify if AddDispatcher was done before calling UseDispatcher/UseEndpoint
// We use the DispatcherMarkerService to make sure if all the services were added.
if (app.ApplicationServices.GetService(typeof(DispatcherMarkerService)) == null)
{
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
nameof(IServiceCollection),
nameof(DispatcherServiceCollectionExtensions.AddDispatcher),
"ConfigureServices(...)"));
}
}
}
}

View File

@ -0,0 +1,58 @@
// 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.Routing;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Builder
{
public static class GlobalRoutingApplicationBuilderExtensions
{
private const string GlobalRoutingRegisteredKey = "__GlobalRoutingMiddlewareRegistered";
// This is provided temporarily until we can remove usages of it from MVC.
public static IApplicationBuilder UseDispatcher(this IApplicationBuilder builder)
{
return UseGlobalRouting(builder);
}
public static IApplicationBuilder UseGlobalRouting(this IApplicationBuilder builder)
{
VerifyRoutingIsRegistered(builder);
builder.Properties[GlobalRoutingRegisteredKey] = true;
return builder.UseMiddleware<GlobalRoutingMiddleware>();
}
public static IApplicationBuilder UseEndpoint(this IApplicationBuilder builder)
{
VerifyRoutingIsRegistered(builder);
if (!builder.Properties.TryGetValue(GlobalRoutingRegisteredKey, out _))
{
var message = $"{nameof(GlobalRoutingMiddleware)} must be added to the request execution pipeline before {nameof(EndpointMiddleware)}. " +
$"Please add {nameof(GlobalRoutingMiddleware)} by calling '{nameof(IApplicationBuilder)}.{nameof(UseGlobalRouting)}' inside the call to 'Configure(...)' in the application startup code.";
throw new InvalidOperationException(message);
}
return builder.UseMiddleware<EndpointMiddleware>();
}
private static void VerifyRoutingIsRegistered(IApplicationBuilder app)
{
// Verify if AddRouting was done before calling UseGlobalRouting/UseEndpoint
// We use the RoutingMarkerService to make sure if all the services were added.
if (app.ApplicationServices.GetService(typeof(RoutingMarkerService)) == null)
{
throw new InvalidOperationException(Resources.FormatUnableToFindServices(
nameof(IServiceCollection),
nameof(RoutingServiceCollectionExtensions.AddRouting),
"ConfigureServices(...)"));
}
}
}
}

View File

@ -69,8 +69,8 @@ namespace Microsoft.AspNetCore.Routing
foreach (var dataSource in _dataSources) foreach (var dataSource in _dataSources)
{ {
Extensions.Primitives.ChangeToken.OnChange( Extensions.Primitives.ChangeToken.OnChange(
() => dataSource.ChangeToken, dataSource.GetChangeToken,
() => HandleChange()); HandleChange);
} }
} }
} }

View File

@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Routing
{ {
lock (_lock) lock (_lock)
{ {
var changeToken = _dataSource.ChangeToken; var changeToken = _dataSource.GetChangeToken();
_value = _initializeCore(_dataSource.Endpoints); _value = _initializeCore(_dataSource.Endpoints);
changeToken.RegisterChangeCallback(_initializerWithState, null); changeToken.RegisterChangeCallback(_initializerWithState, null);

View File

@ -8,11 +8,11 @@ using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
internal class ConfigureDispatcherOptions : IConfigureOptions<DispatcherOptions> internal class ConfigureEndpointOptions : IConfigureOptions<EndpointOptions>
{ {
private readonly IEnumerable<EndpointDataSource> _dataSources; private readonly IEnumerable<EndpointDataSource> _dataSources;
public ConfigureDispatcherOptions(IEnumerable<EndpointDataSource> dataSources) public ConfigureEndpointOptions(IEnumerable<EndpointDataSource> dataSources)
{ {
if (dataSources == null) if (dataSources == null)
{ {
@ -22,7 +22,7 @@ namespace Microsoft.Extensions.DependencyInjection
_dataSources = dataSources; _dataSources = dataSources;
} }
public void Configure(DispatcherOptions options) public void Configure(EndpointOptions options)
{ {
if (options == null) if (options == null)
{ {

View File

@ -2,19 +2,14 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Reflection;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
using Microsoft.AspNetCore.Routing.EndpointFinders;
using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
// This whole class is temporary until we can remove its usage from MVC
public static class DispatcherServiceCollectionExtensions public static class DispatcherServiceCollectionExtensions
{ {
// This whole class is temporary until we can remove its usage from MVC
public static IServiceCollection AddDispatcher(this IServiceCollection services) public static IServiceCollection AddDispatcher(this IServiceCollection services)
{ {
if (services == null) if (services == null)
@ -22,53 +17,21 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(services)); throw new ArgumentNullException(nameof(services));
} }
// Collect all data sources from DI. return services.AddRouting();
services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<DispatcherOptions>, ConfigureDispatcherOptions>());
// Allow global access to the list of endpoints.
services.TryAddSingleton<CompositeEndpointDataSource>(s =>
{
var options = s.GetRequiredService<IOptions<DispatcherOptions>>();
return new CompositeEndpointDataSource(options.Value.DataSources);
});
//
// Default matcher implementation
//
services.TryAddSingleton<MatchProcessorFactory, DefaultMatchProcessorFactory>();
services.TryAddSingleton<MatcherFactory, DfaMatcherFactory>();
services.TryAddTransient<DfaMatcherBuilder>();
// Link generation related services
services.TryAddSingleton<IEndpointFinder<string>, NameBasedEndpointFinder>();
services.TryAddSingleton<IEndpointFinder<RouteValuesBasedEndpointFinderContext>, RouteValuesBasedEndpointFinder>();
services.TryAddSingleton<LinkGenerator, DefaultLinkGenerator>();
//
// Endpoint Selection
//
services.TryAddSingleton<EndpointSelector>();
services.TryAddSingleton<EndpointConstraintCache>();
// Will be cached by the EndpointSelector
services.TryAddEnumerable(
ServiceDescriptor.Transient<IEndpointConstraintProvider, DefaultEndpointConstraintProvider>());
services.TryAddSingleton(typeof(DispatcherMarkerService));
return services;
} }
public static IServiceCollection AddDispatcher(this IServiceCollection services, Action<DispatcherOptions> configuration) // This whole class is temporary until we can remove its usage from MVC
public static IServiceCollection AddDispatcher(this IServiceCollection services, Action<EndpointOptions> configuration)
{ {
if (services == null) if (services == null)
{ {
throw new ArgumentNullException(nameof(services)); throw new ArgumentNullException(nameof(services));
} }
services.AddDispatcher(); services.AddRouting();
if (configuration != null) if (configuration != null)
{ {
services.Configure<DispatcherOptions>(configuration); services.Configure<EndpointOptions>(configuration);
} }
return services; return services;

View File

@ -4,12 +4,15 @@
using System; using System;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Routing.Constraints; using Microsoft.AspNetCore.Routing.Constraints;
using Microsoft.AspNetCore.Routing.EndpointConstraints;
using Microsoft.AspNetCore.Routing.EndpointFinders;
using Microsoft.AspNetCore.Routing.Internal; using Microsoft.AspNetCore.Routing.Internal;
using Microsoft.AspNetCore.Routing.Matchers; using Microsoft.AspNetCore.Routing.Matchers;
using Microsoft.AspNetCore.Routing.Tree; using Microsoft.AspNetCore.Routing.Tree;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.ObjectPool; using Microsoft.Extensions.ObjectPool;
using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection namespace Microsoft.Extensions.DependencyInjection
{ {
@ -49,6 +52,37 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton(typeof(RoutingMarkerService)); services.TryAddSingleton(typeof(RoutingMarkerService));
// Collect all data sources from DI.
services.TryAddEnumerable(ServiceDescriptor.Transient<IConfigureOptions<EndpointOptions>, ConfigureEndpointOptions>());
// Allow global access to the list of endpoints.
services.TryAddSingleton<CompositeEndpointDataSource>(s =>
{
var options = s.GetRequiredService<IOptions<EndpointOptions>>();
return new CompositeEndpointDataSource(options.Value.DataSources);
});
//
// Default matcher implementation
//
services.TryAddSingleton<MatchProcessorFactory, DefaultMatchProcessorFactory>();
services.TryAddSingleton<MatcherFactory, DfaMatcherFactory>();
services.TryAddTransient<DfaMatcherBuilder>();
// Link generation related services
services.TryAddSingleton<IEndpointFinder<string>, NameBasedEndpointFinder>();
services.TryAddSingleton<IEndpointFinder<RouteValuesBasedEndpointFinderContext>, RouteValuesBasedEndpointFinder>();
services.TryAddSingleton<LinkGenerator, DefaultLinkGenerator>();
//
// Endpoint Selection
//
services.TryAddSingleton<EndpointSelector>();
services.TryAddSingleton<EndpointConstraintCache>();
// Will be cached by the EndpointSelector
services.TryAddEnumerable(
ServiceDescriptor.Transient<IEndpointConstraintProvider, DefaultEndpointConstraintProvider>());
return services; return services;
} }

View File

@ -8,7 +8,15 @@ namespace Microsoft.AspNetCore.Routing
{ {
public abstract class EndpointDataSource public abstract class EndpointDataSource
{ {
public abstract IChangeToken ChangeToken { get; } public virtual IChangeToken ChangeToken { get; }
// Plan is to replace ChangeToken property with GetChangeToken
// Temporarily have both to avoid breaking MVC
// https://github.com/aspnet/Routing/issues/634
public virtual IChangeToken GetChangeToken()
{
return ChangeToken;
}
public abstract IReadOnlyList<Endpoint> Endpoints { get; } public abstract IReadOnlyList<Endpoint> Endpoints { get; }
} }

View File

@ -34,8 +34,8 @@ namespace Microsoft.AspNetCore.Routing
var feature = httpContext.Features.Get<IEndpointFeature>(); var feature = httpContext.Features.Get<IEndpointFeature>();
if (feature == null) if (feature == null)
{ {
var message = $"Unable to execute an endpoint because the {nameof(DispatcherMiddleware)} was not run for this request. " + var message = $"Unable to execute an endpoint because the {nameof(GlobalRoutingMiddleware)} was not run for this request. " +
$"Ensure {nameof(DispatcherMiddleware)} is added to the request execution pipeline before {nameof(EndpointMiddleware)} in application startup code."; $"Ensure {nameof(GlobalRoutingMiddleware)} is added to the request execution pipeline before {nameof(EndpointMiddleware)} in application startup code.";
throw new InvalidOperationException(message); throw new InvalidOperationException(message);
} }

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace Microsoft.AspNetCore.Routing namespace Microsoft.AspNetCore.Routing
{ {
public class DispatcherOptions public class EndpointOptions
{ {
public IList<EndpointDataSource> DataSources { get; } = new List<EndpointDataSource>(); public IList<EndpointDataSource> DataSources { get; } = new List<EndpointDataSource>();
} }

View File

@ -11,7 +11,7 @@ using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Routing namespace Microsoft.AspNetCore.Routing
{ {
internal sealed class DispatcherMiddleware internal sealed class GlobalRoutingMiddleware
{ {
private readonly MatcherFactory _matcherFactory; private readonly MatcherFactory _matcherFactory;
private readonly ILogger _logger; private readonly ILogger _logger;
@ -20,10 +20,10 @@ namespace Microsoft.AspNetCore.Routing
private Task<Matcher> _initializationTask; private Task<Matcher> _initializationTask;
public DispatcherMiddleware( public GlobalRoutingMiddleware(
MatcherFactory matcherFactory, MatcherFactory matcherFactory,
CompositeEndpointDataSource endpointDataSource, CompositeEndpointDataSource endpointDataSource,
ILogger<DispatcherMiddleware> logger, ILogger<GlobalRoutingMiddleware> logger,
RequestDelegate next) RequestDelegate next)
{ {
if (matcherFactory == null) if (matcherFactory == null)

View File

@ -1,15 +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.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Routing.Internal
{
/// <summary>
/// A marker class used to determine if all the dispatcher services were added
/// to the <see cref="IServiceCollection"/> before dispatcher is configured.
/// </summary>
internal class DispatcherMarkerService
{
}
}

View File

@ -8,7 +8,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
{ {
/// <summary> /// <summary>
/// An interface for components that can select an <see cref="Endpoint"/> given the current request, as part /// An interface for components that can select an <see cref="Endpoint"/> given the current request, as part
/// of the execution of <see cref="DispatcherMiddleware"/>. /// of the execution of <see cref="GlobalRoutingMiddleware"/>.
/// </summary> /// </summary>
internal abstract class Matcher internal abstract class Matcher
{ {

View File

@ -32,8 +32,8 @@ namespace Microsoft.AspNetCore.Routing
// Register for changes in endpoints // Register for changes in endpoints
Extensions.Primitives.ChangeToken.OnChange( Extensions.Primitives.ChangeToken.OnChange(
() => _endpointDataSource.ChangeToken, _endpointDataSource.GetChangeToken,
() => HandleChange()); HandleChange);
} }
public IEnumerable<Endpoint> FindEndpoints(RouteValuesBasedEndpointFinderContext context) public IEnumerable<Endpoint> FindEndpoints(RouteValuesBasedEndpointFinderContext context)
@ -70,8 +70,8 @@ namespace Microsoft.AspNetCore.Routing
// re-register the callback as the change token is one time use only and a new change token // re-register the callback as the change token is one time use only and a new change token
// is produced every time // is produced every time
Extensions.Primitives.ChangeToken.OnChange( Extensions.Primitives.ChangeToken.OnChange(
() => _endpointDataSource.ChangeToken, _endpointDataSource.GetChangeToken,
() => HandleChange()); HandleChange);
} }
private void BuildOutboundMatches() private void BuildOutboundMatches()

View File

@ -11,20 +11,20 @@ using Xunit;
namespace Microsoft.AspNetCore.Routing.FunctionalTests namespace Microsoft.AspNetCore.Routing.FunctionalTests
{ {
public class DispatcherTest : IDisposable public class GlobalRoutingBenchmarkTest : IDisposable
{ {
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly TestServer _testServer; private readonly TestServer _testServer;
public DispatcherTest() public GlobalRoutingBenchmarkTest()
{ {
// This switch and value are set by benchmark server when running the app for profiling. // This switch and value are set by benchmark server when running the app for profiling.
var args = new[] { "--scenarios", "PlaintextDispatcher" }; var args = new[] { "--scenarios", "PlaintextGlobalRouting" };
var webHostBuilder = Benchmarks.Program.GetWebHostBuilder(args); var webHostBuilder = Benchmarks.Program.GetWebHostBuilder(args);
// Make sure we are using the right startup // Make sure we are using the right startup
var startupName = webHostBuilder.GetSetting("Startup"); var startupName = webHostBuilder.GetSetting("Startup");
Assert.Equal(nameof(Benchmarks.StartupUsingDispatcher), startupName); Assert.Equal(nameof(Benchmarks.StartupUsingGlobalRouting), startupName);
_testServer = new TestServer(webHostBuilder); _testServer = new TestServer(webHostBuilder);
_client = _testServer.CreateClient(); _client = _testServer.CreateClient();

View File

@ -11,12 +11,12 @@ using Xunit;
namespace Microsoft.AspNetCore.Routing.FunctionalTests namespace Microsoft.AspNetCore.Routing.FunctionalTests
{ {
public class RoutingTest : IDisposable public class RouterBenchmarkTest : IDisposable
{ {
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly TestServer _testServer; private readonly TestServer _testServer;
public RoutingTest() public RouterBenchmarkTest()
{ {
// This switch and value are set by benchmark server when running the app for profiling. // This switch and value are set by benchmark server when running the app for profiling.
var args = new[] { "--scenarios", "PlaintextRouting" }; var args = new[] { "--scenarios", "PlaintextRouting" };
@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Routing.FunctionalTests
// Make sure we are using the right startup // Make sure we are using the right startup
var startupName = webHostBuilder.GetSetting("Startup"); var startupName = webHostBuilder.GetSetting("Startup");
Assert.Equal(nameof(Benchmarks.StartupUsingRouting), startupName); Assert.Equal(nameof(Benchmarks.StartupUsingRouter), startupName);
_testServer = new TestServer(webHostBuilder); _testServer = new TestServer(webHostBuilder);
_client = _testServer.CreateClient(); _client = _testServer.CreateClient();

View File

@ -6,18 +6,19 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using RoutingSample.Web;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Routing.FunctionalTests namespace Microsoft.AspNetCore.Routing.FunctionalTests
{ {
public class DispatcherSampleTest : IDisposable public class GlobalRoutingSampleTest : IDisposable
{ {
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly TestServer _testServer; private readonly TestServer _testServer;
public DispatcherSampleTest() public GlobalRoutingSampleTest()
{ {
var webHostBuilder = DispatcherSample.Web.Program.GetWebHostBuilder(); var webHostBuilder = Program.GetWebHostBuilder(new[] { Program.GlobalRoutingScenario, });
_testServer = new TestServer(webHostBuilder); _testServer = new TestServer(webHostBuilder);
_client = _testServer.CreateClient(); _client = _testServer.CreateClient();
_client.BaseAddress = new Uri("http://localhost"); _client.BaseAddress = new Uri("http://localhost");
@ -28,7 +29,7 @@ namespace Microsoft.AspNetCore.Routing.FunctionalTests
{ {
// Arrange // Arrange
var expectedContentType = "text/plain"; var expectedContentType = "text/plain";
var expectedContent = "Dispatcher sample endpoints:" + Environment.NewLine + "/plaintext"; var expectedContent = "Global Routing sample endpoints:" + Environment.NewLine + "/plaintext";
// Act // Act
var response = await _client.GetAsync("/"); var response = await _client.GetAsync("/");

View File

@ -7,7 +7,6 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Routing\Microsoft.AspNetCore.Routing.csproj" /> <ProjectReference Include="..\..\src\Microsoft.AspNetCore.Routing\Microsoft.AspNetCore.Routing.csproj" />
<ProjectReference Include="..\..\samples\RoutingSample.Web\RoutingSample.Web.csproj" /> <ProjectReference Include="..\..\samples\RoutingSample.Web\RoutingSample.Web.csproj" />
<ProjectReference Include="..\..\samples\DispatcherSample.Web\DispatcherSample.Web.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -6,18 +6,19 @@ using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.TestHost; using Microsoft.AspNetCore.TestHost;
using RoutingSample.Web;
using Xunit; using Xunit;
namespace Microsoft.AspNetCore.Routing.FunctionalTests namespace Microsoft.AspNetCore.Routing.FunctionalTests
{ {
public class RoutingSampleTest : IDisposable public class RouterSampleTest : IDisposable
{ {
private readonly HttpClient _client; private readonly HttpClient _client;
private readonly TestServer _testServer; private readonly TestServer _testServer;
public RoutingSampleTest() public RouterSampleTest()
{ {
var webHostBuilder = RoutingSample.Web.Program.GetWebHostBuilder(); var webHostBuilder = Program.GetWebHostBuilder(new[] { Program.RouterScenario, });
_testServer = new TestServer(webHostBuilder); _testServer = new TestServer(webHostBuilder);
_client = _testServer.CreateClient(); _client = _testServer.CreateClient();
_client.BaseAddress = new Uri("http://localhost"); _client.BaseAddress = new Uri("http://localhost");

View File

@ -12,21 +12,21 @@ using Xunit;
namespace Microsoft.AspNetCore.Builder namespace Microsoft.AspNetCore.Builder
{ {
public class DispatcherApplicationBuilderExtensionsTest public class GlobalRoutingBuilderExtensionsTest
{ {
[Fact] [Fact]
public void UseDispatcher_ServicesNotRegistered_Throws() public void UseGlobalRouting_ServicesNotRegistered_Throws()
{ {
// Arrange // Arrange
var app = new ApplicationBuilder(Mock.Of<IServiceProvider>()); var app = new ApplicationBuilder(Mock.Of<IServiceProvider>());
// Act // Act
var ex = Assert.Throws<InvalidOperationException>(() => app.UseDispatcher()); var ex = Assert.Throws<InvalidOperationException>(() => app.UseGlobalRouting());
// Assert // Assert
Assert.Equal( Assert.Equal(
"Unable to find the required services. " + "Unable to find the required services. " +
"Please add all the required services by calling 'IServiceCollection.AddDispatcher' " + "Please add all the required services by calling 'IServiceCollection.AddRouting' " +
"inside the call to 'ConfigureServices(...)' in the application startup code.", "inside the call to 'ConfigureServices(...)' in the application startup code.",
ex.Message); ex.Message);
} }
@ -43,20 +43,20 @@ namespace Microsoft.AspNetCore.Builder
// Assert // Assert
Assert.Equal( Assert.Equal(
"Unable to find the required services. " + "Unable to find the required services. " +
"Please add all the required services by calling 'IServiceCollection.AddDispatcher' " + "Please add all the required services by calling 'IServiceCollection.AddRouting' " +
"inside the call to 'ConfigureServices(...)' in the application startup code.", "inside the call to 'ConfigureServices(...)' in the application startup code.",
ex.Message); ex.Message);
} }
[Fact] [Fact]
public async Task UseDispatcher_ServicesRegistered_SetsFeature() public async Task UseGlobalRouting_ServicesRegistered_SetsFeature()
{ {
// Arrange // Arrange
var services = CreateServices(); var services = CreateServices();
var app = new ApplicationBuilder(services); var app = new ApplicationBuilder(services);
app.UseDispatcher(); app.UseGlobalRouting();
var appFunc = app.Build(); var appFunc = app.Build();
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
@ -69,7 +69,7 @@ namespace Microsoft.AspNetCore.Builder
} }
[Fact] [Fact]
public void UseEndpoint_ServicesRegisteredAndNoDispatcherRegistered_Throws() public void UseEndpoint_WithoutRoutingServicesRegistered_Throws()
{ {
// Arrange // Arrange
var services = CreateServices(); var services = CreateServices();
@ -81,21 +81,21 @@ namespace Microsoft.AspNetCore.Builder
// Assert // Assert
Assert.Equal( Assert.Equal(
"DispatcherMiddleware must be added to the request execution pipeline before EndpointMiddleware. " + "GlobalRoutingMiddleware must be added to the request execution pipeline before EndpointMiddleware. " +
"Please add DispatcherMiddleware by calling 'IApplicationBuilder.UseDispatcher' " + "Please add GlobalRoutingMiddleware by calling 'IApplicationBuilder.UseGlobalRouting' " +
"inside the call to 'Configure(...)' in the application startup code.", "inside the call to 'Configure(...)' in the application startup code.",
ex.Message); ex.Message);
} }
[Fact] [Fact]
public async Task UseEndpoint_ServicesRegisteredAndDispatcherRegistered_SetsFeature() public async Task UseEndpoint_ServicesRegisteredAndGlobalRoutingRegistered_SetsFeature()
{ {
// Arrange // Arrange
var services = CreateServices(); var services = CreateServices();
var app = new ApplicationBuilder(services); var app = new ApplicationBuilder(services);
app.UseDispatcher(); app.UseGlobalRouting();
app.UseEndpoint(); app.UseEndpoint();
var appFunc = app.Build(); var appFunc = app.Build();
@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Builder
services.AddLogging(); services.AddLogging();
services.AddOptions(); services.AddOptions();
services.AddDispatcher(); services.AddRouting();
return services.BuildServiceProvider(); return services.BuildServiceProvider();
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved. // Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
@ -14,6 +14,28 @@ namespace Microsoft.AspNetCore.Builder
{ {
public class RoutingBuilderExtensionsTest public class RoutingBuilderExtensionsTest
{ {
[Fact]
public void UseRouter_ThrowsInvalidOperationException_IfRoutingMarkerServiceIsNotRegistered()
{
// Arrange
var applicationBuilderMock = new Mock<IApplicationBuilder>();
applicationBuilderMock
.Setup(s => s.ApplicationServices)
.Returns(Mock.Of<IServiceProvider>());
var router = Mock.Of<IRouter>();
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
() => applicationBuilderMock.Object.UseRouter(router));
Assert.Equal(
"Unable to find the required services. Please add all the required services by calling " +
"'IServiceCollection.AddRouting' inside the call to 'ConfigureServices(...)'" +
" in the application startup code.",
exception.Message);
}
[Fact] [Fact]
public void UseRouter_IRouter_ThrowsWithoutCallingAddRouting() public void UseRouter_IRouter_ThrowsWithoutCallingAddRouting()
{ {
@ -59,7 +81,7 @@ namespace Microsoft.AspNetCore.Builder
var router = new Mock<IRouter>(MockBehavior.Strict); var router = new Mock<IRouter>(MockBehavior.Strict);
router router
.Setup(r => r.RouteAsync(It.IsAny<RouteContext>())) .Setup(r => r.RouteAsync(It.IsAny<RouteContext>()))
.Returns(Task.FromResult(0)) .Returns(Task.CompletedTask)
.Verifiable(); .Verifiable();
app.UseRouter(router.Object); app.UseRouter(router.Object);
@ -84,7 +106,7 @@ namespace Microsoft.AspNetCore.Builder
var router = new Mock<IRouter>(MockBehavior.Strict); var router = new Mock<IRouter>(MockBehavior.Strict);
router router
.Setup(r => r.RouteAsync(It.IsAny<RouteContext>())) .Setup(r => r.RouteAsync(It.IsAny<RouteContext>()))
.Returns(Task.FromResult(0)) .Returns(Task.CompletedTask)
.Verifiable(); .Verifiable();
app.UseRouter(b => app.UseRouter(b =>

View File

@ -1,35 +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.Routing;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Builder
{
public class BuilderExtensionsTest
{
[Fact]
public void UseRouter_ThrowsInvalidOperationException_IfRoutingMarkerServiceIsNotRegistered()
{
// Arrange
var applicationBuilderMock = new Mock<IApplicationBuilder>();
applicationBuilderMock
.Setup(s => s.ApplicationServices)
.Returns(Mock.Of<IServiceProvider>());
var router = Mock.Of<IRouter>();
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(
() => applicationBuilderMock.Object.UseRouter(router));
Assert.Equal(
"Unable to find the required services. Please add all the required services by calling " +
"'IServiceCollection.AddRouting' inside the call to 'ConfigureServices(...)'" +
" in the application startup code.",
exception.Message);
}
}
}

View File

@ -114,7 +114,7 @@ namespace Microsoft.AspNetCore.Routing
var endpoints = compositeDataSource.Endpoints; var endpoints = compositeDataSource.Endpoints;
// Assert1 // Assert1
var changeToken1 = compositeDataSource.ChangeToken; var changeToken1 = compositeDataSource.GetChangeToken();
var token = Assert.IsType<CancellationChangeToken>(changeToken1); var token = Assert.IsType<CancellationChangeToken>(changeToken1);
Assert.False(token.HasChanged); // initial state Assert.False(token.HasChanged); // initial state
@ -126,7 +126,7 @@ namespace Microsoft.AspNetCore.Routing
// Assert2 // Assert2
Assert.True(changeToken1.HasChanged); // old token is expected to be changed Assert.True(changeToken1.HasChanged); // old token is expected to be changed
var changeToken2 = compositeDataSource.ChangeToken; // new token is in a unchanged state var changeToken2 = compositeDataSource.GetChangeToken(); // new token is in a unchanged state
Assert.NotSame(changeToken2, changeToken1); Assert.NotSame(changeToken2, changeToken1);
token = Assert.IsType<CancellationChangeToken>(changeToken2); token = Assert.IsType<CancellationChangeToken>(changeToken2);
Assert.False(token.HasChanged); Assert.False(token.HasChanged);
@ -139,7 +139,7 @@ namespace Microsoft.AspNetCore.Routing
// Assert2 // Assert2
Assert.True(changeToken2.HasChanged); // old token is expected to be changed Assert.True(changeToken2.HasChanged); // old token is expected to be changed
var changeToken3 = compositeDataSource.ChangeToken; // new token is in a unchanged state var changeToken3 = compositeDataSource.GetChangeToken(); // new token is in a unchanged state
Assert.NotSame(changeToken3, changeToken2); Assert.NotSame(changeToken3, changeToken2);
Assert.NotSame(changeToken3, changeToken1); Assert.NotSame(changeToken3, changeToken1);
token = Assert.IsType<CancellationChangeToken>(changeToken3); token = Assert.IsType<CancellationChangeToken>(changeToken3);

View File

@ -35,8 +35,9 @@ namespace Microsoft.AspNetCore.Routing
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await invokeTask); var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await invokeTask);
Assert.Equal( Assert.Equal(
"Unable to execute an endpoint because the DispatcherMiddleware was not run for this request. " + "Unable to execute an endpoint because the GlobalRoutingMiddleware was not run for this request. " +
"Ensure DispatcherMiddleware is added to the request execution pipeline before EndpointMiddleware in application startup code.", "Ensure GlobalRoutingMiddleware is added to the request execution pipeline before EndpointMiddleware " +
"in application startup code.",
ex.Message); ex.Message);
} }

View File

@ -13,7 +13,7 @@ using Xunit;
namespace Microsoft.AspNetCore.Routing namespace Microsoft.AspNetCore.Routing
{ {
public class DispatcherMiddlewareTest public class GlobalRoutingMiddlewareTest
{ {
[Fact] [Fact]
public async Task Invoke_OnCall_SetsEndpointFeature() public async Task Invoke_OnCall_SetsEndpointFeature()
@ -39,14 +39,14 @@ namespace Microsoft.AspNetCore.Routing
var expectedMessage = "Request matched endpoint 'Test endpoint'."; var expectedMessage = "Request matched endpoint 'Test endpoint'.";
var sink = new TestSink( var sink = new TestSink(
TestSink.EnableWithTypeName<DispatcherMiddleware>, TestSink.EnableWithTypeName<GlobalRoutingMiddleware>,
TestSink.EnableWithTypeName<DispatcherMiddleware>); TestSink.EnableWithTypeName<GlobalRoutingMiddleware>);
var loggerFactory = new TestLoggerFactory(sink, enabled: true); var loggerFactory = new TestLoggerFactory(sink, enabled: true);
var httpContext = new DefaultHttpContext(); var httpContext = new DefaultHttpContext();
httpContext.RequestServices = new TestServiceProvider(); httpContext.RequestServices = new TestServiceProvider();
var logger = new Logger<DispatcherMiddleware>(loggerFactory); var logger = new Logger<GlobalRoutingMiddleware>(loggerFactory);
var middleware = CreateMiddleware(logger); var middleware = CreateMiddleware(logger);
// Act // Act
@ -82,15 +82,15 @@ namespace Microsoft.AspNetCore.Routing
Assert.Equal("testValue", endpointFeature.Values["testKey"]); Assert.Equal("testValue", endpointFeature.Values["testKey"]);
} }
private DispatcherMiddleware CreateMiddleware(Logger<DispatcherMiddleware> logger = null) private GlobalRoutingMiddleware CreateMiddleware(Logger<GlobalRoutingMiddleware> logger = null)
{ {
RequestDelegate next = (c) => Task.FromResult<object>(null); RequestDelegate next = (c) => Task.FromResult<object>(null);
logger = logger ?? new Logger<DispatcherMiddleware>(NullLoggerFactory.Instance); logger = logger ?? new Logger<GlobalRoutingMiddleware>(NullLoggerFactory.Instance);
var options = Options.Create(new DispatcherOptions()); var options = Options.Create(new EndpointOptions());
var matcherFactory = new TestMatcherFactory(true); var matcherFactory = new TestMatcherFactory(true);
var middleware = new DispatcherMiddleware( var middleware = new GlobalRoutingMiddleware(
matcherFactory, matcherFactory,
new CompositeEndpointDataSource(Array.Empty<EndpointDataSource>()), new CompositeEndpointDataSource(Array.Empty<EndpointDataSource>()),
logger, logger,

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints) internal override Matcher CreateMatcher(params MatcherEndpoint[] endpoints)
@ -29,7 +29,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
.AddLogging() .AddLogging()
.AddOptions() .AddOptions()
.AddRouting() .AddRouting()
.AddDispatcher()
.BuildServiceProvider(); .BuildServiceProvider();
var builder = services.GetRequiredService<DfaMatcherBuilder>(); var builder = services.GetRequiredService<DfaMatcherBuilder>();

View File

@ -36,7 +36,6 @@ namespace Microsoft.AspNetCore.Routing.Matchers
.AddLogging() .AddLogging()
.AddOptions() .AddOptions()
.AddRouting() .AddRouting()
.AddDispatcher()
.BuildServiceProvider(); .BuildServiceProvider();
var factory = services.GetRequiredService<MatcherFactory>(); var factory = services.GetRequiredService<MatcherFactory>();

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
[Fact] [Fact]
@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", }); MatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", });
} }
[Fact] [Fact]
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", d = "19" }); MatcherAssert.AssertMatch(feature, endpoint, new { b = "17", c = "18", d = "19" });
} }
[Theory] [Theory]
@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
[Theory] [Theory]
@ -121,7 +121,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
[Theory] [Theory]
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
[Theory] [Theory]
@ -168,7 +168,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
// Historically catchall segments don't match an empty segment, but only if it's // Historically catchall segments don't match an empty segment, but only if it's
@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
// Need to access these to prevent a warning from the xUnit analyzer. // Need to access these to prevent a warning from the xUnit analyzer.
// Some of these tests will match (and process the values) and some will not. // Some of these tests will match (and process the values) and some will not.
@ -223,7 +223,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
[Theory] [Theory]
@ -243,7 +243,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
[Theory] [Theory]
@ -272,7 +272,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
[Theory] [Theory]
@ -298,7 +298,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
// Most of are copied from old routing tests that date back to the VS 2010 era. Enjoy! // Most of are copied from old routing tests that date back to the VS 2010 era. Enjoy!
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
[Theory] [Theory]
@ -353,7 +353,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, expected, ignoreValues: true); MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
} }
[Theory] [Theory]
@ -387,7 +387,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, expected, ignoreValues: true); MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
} }
[Theory] [Theory]
@ -440,7 +440,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, expected, ignoreValues: true); MatcherAssert.AssertMatch(feature, expected, ignoreValues: true);
} }
} }
} }

View File

@ -8,7 +8,7 @@ using Xunit.Sdk;
namespace Microsoft.AspNetCore.Routing.Matchers namespace Microsoft.AspNetCore.Routing.Matchers
{ {
internal static class DispatcherAssert internal static class MatcherAssert
{ {
public static void AssertMatch(IEndpointFeature feature, Endpoint expected) public static void AssertMatch(IEndpointFeature feature, Endpoint expected)
{ {

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
[Fact] [Fact]
@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
[Fact] [Fact]
@ -47,7 +47,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
[Theory] [Theory]
@ -64,7 +64,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
// Some matchers will optimize for the ASCII case // Some matchers will optimize for the ASCII case
@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
// Matchers should operate on the decoded representation - a matcher that calls // Matchers should operate on the decoded representation - a matcher that calls
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
[Theory] [Theory]
@ -119,7 +119,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
[Theory] [Theory]
@ -136,7 +136,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
// Matchers do their own 'splitting' of the path into segments, so including // Matchers do their own 'splitting' of the path into segments, so including
@ -159,7 +159,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint); MatcherAssert.AssertMatch(feature, endpoint);
} }
// Matchers do their own 'splitting' of the path into segments, so including // Matchers do their own 'splitting' of the path into segments, so including
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
[Fact] [Fact]
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, values); MatcherAssert.AssertMatch(feature, endpoint, values);
} }
[Fact] [Fact]
@ -220,7 +220,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, values); MatcherAssert.AssertMatch(feature, endpoint, values);
} }
[Fact] [Fact]
@ -235,7 +235,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, values); MatcherAssert.AssertMatch(feature, endpoint, values);
} }
[Fact] [Fact]
@ -255,7 +255,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, values); MatcherAssert.AssertMatch(feature, endpoint, values);
} }
[Theory] [Theory]
@ -273,7 +273,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
[Theory] [Theory]
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertMatch(feature, endpoint, keys, values); MatcherAssert.AssertMatch(feature, endpoint, keys, values);
} }
[Theory] [Theory]
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Routing.Matchers
await matcher.MatchAsync(httpContext, feature); await matcher.MatchAsync(httpContext, feature);
// Assert // Assert
DispatcherAssert.AssertNotMatch(feature); MatcherAssert.AssertNotMatch(feature);
} }
} }
} }

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Routing
// add routes that behave as advertised. // add routes that behave as advertised.
public class RequestDelegateRouteBuilderExtensionsTest public class RequestDelegateRouteBuilderExtensionsTest
{ {
private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0); private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask;
public static TheoryData<Action<IRouteBuilder>, Action<HttpContext>> MatchingActions public static TheoryData<Action<IRouteBuilder>, Action<HttpContext>> MatchingActions
{ {

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Routing
{ {
public class RouteCollectionTest public class RouteCollectionTest
{ {
private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0); private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask;
[Theory] [Theory]
[InlineData(@"Home/Index/23", "/home/index/23", true, false)] [InlineData(@"Home/Index/23", "/home/index/23", true, false)]

View File

@ -24,7 +24,7 @@ namespace Microsoft.AspNetCore.Routing
{ {
public class RouteTest public class RouteTest
{ {
private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0); private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask;
private static IInlineConstraintResolver _inlineConstraintResolver = GetInlineConstraintResolver(); private static IInlineConstraintResolver _inlineConstraintResolver = GetInlineConstraintResolver();
[Fact] [Fact]

View File

@ -90,7 +90,7 @@ namespace Microsoft.AspNetCore.Routing
public Task RouteAsync(RouteContext context) public Task RouteAsync(RouteContext context)
{ {
context.Handler = _isHandled ? (RequestDelegate)((c) => Task.FromResult(0)) : null; context.Handler = _isHandled ? (RequestDelegate)((c) => Task.CompletedTask) : null;
return Task.FromResult<object>(null); return Task.FromResult<object>(null);
} }
} }

View File

@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
{ {
public class TreeRouterTest public class TreeRouterTest
{ {
private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0); private static readonly RequestDelegate NullHandler = (c) => Task.CompletedTask;
private static ObjectPool<UriBuildingContext> Pool = new DefaultObjectPoolProvider().Create( private static ObjectPool<UriBuildingContext> Pool = new DefaultObjectPoolProvider().Create(
new UriBuilderContextPooledObjectPolicy()); new UriBuilderContextPooledObjectPolicy());
@ -1820,7 +1820,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
nestedRouters = new List<IRouter>(c.RouteData.Routers); nestedRouters = new List<IRouter>(c.RouteData.Routers);
c.Handler = null; // Not a match c.Handler = null; // Not a match
}) })
.Returns(Task.FromResult(0)); .Returns(Task.CompletedTask);
var builder = CreateBuilder(); var builder = CreateBuilder();
MapInboundEntry(builder, "api/Store", handler: next.Object); MapInboundEntry(builder, "api/Store", handler: next.Object);
@ -1857,7 +1857,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
nestedRouters = new List<IRouter>(c.RouteData.Routers); nestedRouters = new List<IRouter>(c.RouteData.Routers);
c.Handler = null; // Not a match c.Handler = null; // Not a match
}) })
.Returns(Task.FromResult(0)); .Returns(Task.CompletedTask);
var builder = CreateBuilder(); var builder = CreateBuilder();
MapInboundEntry(builder, "api/Store", handler: next.Object); MapInboundEntry(builder, "api/Store", handler: next.Object);
@ -1901,7 +1901,7 @@ namespace Microsoft.AspNetCore.Routing.Tree
nestedRouters = new List<IRouter>(c.RouteData.Routers); nestedRouters = new List<IRouter>(c.RouteData.Routers);
throw new Exception(); throw new Exception();
}) })
.Returns(Task.FromResult(0)); .Returns(Task.CompletedTask);
var builder = CreateBuilder(); var builder = CreateBuilder();
MapInboundEntry(builder, "api/Store", handler: next.Object); MapInboundEntry(builder, "api/Store", handler: next.Object);