diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json
index e2ec6646ab..787d2fec4b 100644
--- a/NuGetPackageVerifier.json
+++ b/NuGetPackageVerifier.json
@@ -10,6 +10,7 @@
],
"packages": {
"Microsoft.AspNet.Routing.Abstractions": { },
+ "Microsoft.AspNet.Routing.Extensions": { },
"Microsoft.AspNet.Routing": { }
}
},
diff --git a/Routing.sln b/Routing.sln
index b0596d1297..cebcc0d01f 100644
--- a/Routing.sln
+++ b/Routing.sln
@@ -28,6 +28,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Routing.Ab
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Routing.Abstractions.Tests", "test\Microsoft.AspNet.Mvc.Routing.Abstractions.Tests\Microsoft.AspNet.Mvc.Routing.Abstractions.Tests.xproj", "{741B0B05-CE96-473B-B962-6B0A347DF79A}"
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Routing.Extensions", "src\Microsoft.AspNet.Routing.Extensions\Microsoft.AspNet.Routing.Extensions.xproj", "{579C3FD2-DFFA-4B64-BFC3-130C11F3568F}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Routing.Extensions.Tests", "test\Microsoft.AspNet.Routing.Extensions.Tests\Microsoft.AspNet.Routing.Extensions.Tests.xproj", "{FD0151B4-7153-49A8-9D90-62A252420230}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -116,6 +120,30 @@ Global
{741B0B05-CE96-473B-B962-6B0A347DF79A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{741B0B05-CE96-473B-B962-6B0A347DF79A}.Release|x86.ActiveCfg = Release|Any CPU
{741B0B05-CE96-473B-B962-6B0A347DF79A}.Release|x86.Build.0 = Release|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Debug|x86.Build.0 = Debug|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Release|x86.ActiveCfg = Release|Any CPU
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F}.Release|x86.Build.0 = Release|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Debug|x86.Build.0 = Debug|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Release|x86.ActiveCfg = Release|Any CPU
+ {FD0151B4-7153-49A8-9D90-62A252420230}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -128,5 +156,7 @@ Global
{09C2933C-23AC-41B7-994D-E8A5184A629C} = {95359B4B-4C85-4B44-A75B-0621905C4CF6}
{ED253B01-24F1-43D1-AA0B-079391E105A9} = {0E966C37-7334-4D96-AAF6-9F49FBD166E3}
{741B0B05-CE96-473B-B962-6B0A347DF79A} = {95359B4B-4C85-4B44-A75B-0621905C4CF6}
+ {579C3FD2-DFFA-4B64-BFC3-130C11F3568F} = {0E966C37-7334-4D96-AAF6-9F49FBD166E3}
+ {FD0151B4-7153-49A8-9D90-62A252420230} = {95359B4B-4C85-4B44-A75B-0621905C4CF6}
EndGlobalSection
EndGlobal
diff --git a/samples/RoutingSample.Web/Startup.cs b/samples/RoutingSample.Web/Startup.cs
index 416d1b4c2d..6ee715cead 100644
--- a/samples/RoutingSample.Web/Startup.cs
+++ b/samples/RoutingSample.Web/Startup.cs
@@ -1,6 +1,8 @@
// 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.Globalization;
+using System.Threading;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing;
@@ -15,7 +17,7 @@ namespace RoutingSample.Web
services.AddRouting();
}
- public void Configure(IApplicationBuilder builder)
+ public void Configure(IApplicationBuilder app)
{
var endpoint1 = new RouteHandler((c) =>
{
@@ -24,12 +26,30 @@ namespace RoutingSample.Web
var endpoint2 = new RouteHandler((c) => c.Response.WriteAsync("Hello, World!"));
- var routeBuilder = new RouteBuilder()
+ var routeBuilder = new RouteBuilder(app)
{
DefaultHandler = endpoint1,
- ServiceProvider = builder.ApplicationServices,
};
+ routeBuilder.MapRoute("api/status/{item}", c => c.Response.WriteAsync($"{c.GetRouteValue("item")} is just fine."));
+ routeBuilder.MapRoute("localized/{lang=en-US}", b =>
+ {
+ b.Use(next => async (c) =>
+ {
+ var culture = new CultureInfo((string)c.GetRouteValue("lang"));
+#if DNX451
+ Thread.CurrentThread.CurrentCulture = culture;
+ Thread.CurrentThread.CurrentUICulture = culture;
+#else
+ CultureInfo.CurrentCulture = culture;
+ CultureInfo.CurrentUICulture = culture;
+#endif
+ await next(c);
+ });
+
+ b.Run(c => c.Response.WriteAsync($"What would you do with {1000000m:C}?"));
+ });
+
routeBuilder.AddPrefixRoute("api/store", endpoint1);
routeBuilder.AddPrefixRoute("hello/world", endpoint2);
@@ -38,7 +58,7 @@ namespace RoutingSample.Web
routeBuilder.AddPrefixRoute("", endpoint2);
- builder.UseRouter(routeBuilder.Build());
+ app.UseRouter(routeBuilder.Build());
}
}
}
\ No newline at end of file
diff --git a/samples/RoutingSample.Web/project.json b/samples/RoutingSample.Web/project.json
index c82801ee6d..bdd39222cd 100644
--- a/samples/RoutingSample.Web/project.json
+++ b/samples/RoutingSample.Web/project.json
@@ -1,16 +1,15 @@
{
- "dependencies": {
- "Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
- "Microsoft.AspNet.Server.WebListener": "1.0.0-*",
- "Microsoft.AspNet.Routing": "1.0.0-*"
- },
- "commands": {
- "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
- "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
- },
- "frameworks": {
- "dnx451": { },
- "dnxcore50": { }
- },
- "webroot": "wwwroot"
+ "dependencies": {
+ "Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
+ "Microsoft.AspNet.Server.WebListener": "1.0.0-*",
+ "Microsoft.AspNet.Routing.Extensions": "1.0.0-*"
+ },
+ "commands": {
+ "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
+ "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
+ },
+ "frameworks": {
+ "dnx451": { },
+ "dnxcore50": { }
+ }
}
diff --git a/samples/RoutingSample.Web/wwwroot/ReadMe.md b/samples/RoutingSample.Web/wwwroot/ReadMe.md
deleted file mode 100644
index 6fcb35323e..0000000000
--- a/samples/RoutingSample.Web/wwwroot/ReadMe.md
+++ /dev/null
@@ -1 +0,0 @@
-RoutingSample.Web
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Routing.Extensions/Microsoft.AspNet.Routing.Extensions.xproj b/src/Microsoft.AspNet.Routing.Extensions/Microsoft.AspNet.Routing.Extensions.xproj
new file mode 100644
index 0000000000..5ad562b4eb
--- /dev/null
+++ b/src/Microsoft.AspNet.Routing.Extensions/Microsoft.AspNet.Routing.Extensions.xproj
@@ -0,0 +1,20 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+
+ 579c3fd2-dffa-4b64-bfc3-130c11f3568f
+ Microsoft.AspNet.Routing.Extensions
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+
+ 2.0
+
+
+
diff --git a/src/Microsoft.AspNet.Routing.Extensions/Properties/AssemblyInfo.cs b/src/Microsoft.AspNet.Routing.Extensions/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..e0f545c6b5
--- /dev/null
+++ b/src/Microsoft.AspNet.Routing.Extensions/Properties/AssemblyInfo.cs
@@ -0,0 +1,8 @@
+// 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 System.Resources;
+
+[assembly: AssemblyMetadata("Serviceable", "True")]
+[assembly: NeutralResourcesLanguage("en-us")]
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Routing.Extensions/RequestDelegateRouteBuilderExtensions.cs b/src/Microsoft.AspNet.Routing.Extensions/RequestDelegateRouteBuilderExtensions.cs
new file mode 100644
index 0000000000..4624bf6d66
--- /dev/null
+++ b/src/Microsoft.AspNet.Routing.Extensions/RequestDelegateRouteBuilderExtensions.cs
@@ -0,0 +1,207 @@
+// 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.AspNet.Http;
+using Microsoft.AspNet.Routing;
+using Microsoft.AspNet.Routing.Constraints;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.AspNet.Builder
+{
+ public static class RequestDelegateRouteBuilderExtensions
+ {
+ ///
+ /// Adds a route to the for the given , and
+ /// .
+ ///
+ /// The .
+ /// The route template.
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapRoute(this IRouteBuilder builder, string template, RequestDelegate handler)
+ {
+ var route = new Route(
+ new RouteHandler(handler),
+ template,
+ defaults: null,
+ constraints: null,
+ dataTokens: null,
+ inlineConstraintResolver: GetConstraintResolver(builder));
+
+ builder.Routes.Add(route);
+ return builder;
+ }
+
+ ///
+ /// Adds a route to the for the given , and
+ /// .
+ ///
+ /// The .
+ /// The action to apply to the .
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapRoute(this IRouteBuilder builder, string template, Action action)
+ {
+ var nested = builder.ApplicationBuilder.New();
+ action(nested);
+ return builder.MapRoute(template, nested.Build());
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapDelete(this IRouteBuilder builder, string template, RequestDelegate handler)
+ {
+ return builder.MapVerb("DELETE", template, handler);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The action to apply to the .
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapDelete(this IRouteBuilder builder, string template, Action action)
+ {
+ return builder.MapVerb("DELETE", template, action);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapGet(this IRouteBuilder builder, string template, RequestDelegate handler)
+ {
+ return builder.MapVerb("GET", template, handler);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The action to apply to the .
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapGet(this IRouteBuilder builder, string template, Action action)
+ {
+ return builder.MapVerb("GET", template, action);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapPost(this IRouteBuilder builder, string template, RequestDelegate handler)
+ {
+ return builder.MapVerb("POST", template, handler);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The action to apply to the .
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapPost(this IRouteBuilder builder, string template, Action action)
+ {
+ return builder.MapVerb("POST", template, action);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapPut(this IRouteBuilder builder, string template, RequestDelegate handler)
+ {
+ return builder.MapVerb("PUT", template, handler);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP DELETE requests for the given
+ /// , and .
+ ///
+ /// The .
+ /// The route template.
+ /// The action to apply to the .
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapPut(this IRouteBuilder builder, string template, Action action)
+ {
+ return builder.MapVerb("PUT", template, action);
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP requests for the given
+ /// , , and .
+ ///
+ /// The .
+ /// The HTTP verb allowed by the route.
+ /// The route template.
+ /// The route handler.
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapVerb(
+ this IRouteBuilder builder,
+ string verb,
+ string template,
+ RequestDelegate handler)
+ {
+ var route = new Route(
+ new RouteHandler(handler),
+ template,
+ defaults: null,
+ constraints: new RouteValueDictionary(new { httpMethod = new HttpMethodRouteConstraint(verb) }),
+ dataTokens: null,
+ inlineConstraintResolver: GetConstraintResolver(builder));
+
+ builder.Routes.Add(route);
+ return builder;
+ }
+
+ ///
+ /// Adds a route to the that only matches HTTP requests for the given
+ /// , , and .
+ ///
+ /// The .
+ /// The HTTP verb allowed by the route.
+ /// The route template.
+ /// The action to apply to the .
+ /// A reference to the after this operation has completed.
+ public static IRouteBuilder MapVerb(
+ this IRouteBuilder builder,
+ string verb,
+ string template,
+ Action action)
+ {
+ var nested = builder.ApplicationBuilder.New();
+ action(nested);
+ return builder.MapVerb(verb, template, nested.Build());
+ }
+
+ private static IInlineConstraintResolver GetConstraintResolver(IRouteBuilder builder)
+ {
+ return builder.ServiceProvider.GetRequiredService();
+ }
+ }
+}
diff --git a/src/Microsoft.AspNet.Routing.Extensions/project.json b/src/Microsoft.AspNet.Routing.Extensions/project.json
new file mode 100644
index 0000000000..6d1132e6d4
--- /dev/null
+++ b/src/Microsoft.AspNet.Routing.Extensions/project.json
@@ -0,0 +1,19 @@
+{
+ "description": "ASP.NET 5 extension methods for routing requests to application logic and for generating links.",
+ "version": "1.0.0-*",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/aspnet/routing"
+ },
+ "compilationOptions": {
+ "warningsAsErrors": true,
+ "keyFile": "../../tools/Key.snk"
+ },
+ "dependencies": {
+ "Microsoft.AspNet.Routing": "1.0.0-*"
+ },
+ "frameworks": {
+ "net451": { },
+ "dotnet5.4": { }
+ }
+}
diff --git a/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs b/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs
index e6a248189a..d211f06ce5 100644
--- a/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs
+++ b/src/Microsoft.AspNet.Routing/Constraints/HttpMethodRouteConstraint.cs
@@ -11,14 +11,14 @@ namespace Microsoft.AspNet.Routing.Constraints
///
/// Constrains the HTTP method of request or a route.
///
- public class HttpRouteMethodConstraint : IRouteConstraint
+ public class HttpMethodRouteConstraint : IRouteConstraint
{
///
- /// Creates a new that accepts the HTTP methods specified
+ /// Creates a new that accepts the HTTP methods specified
/// by .
///
/// The allowed HTTP methods.
- public HttpRouteMethodConstraint(params string[] allowedMethods)
+ public HttpMethodRouteConstraint(params string[] allowedMethods)
{
if (allowedMethods == null)
{
@@ -69,8 +69,8 @@ namespace Microsoft.AspNet.Routing.Constraints
case RouteDirection.UrlGeneration:
// We need to see if the user specified the HTTP method explicitly. Consider these two routes:
//
- // a) Route: template = "/{foo}", Constraints = { httpMethod = new HttpRouteMethodConstraint("GET") }
- // b) Route: template = "/{foo}", Constraints = { httpMethod = new HttpRouteMethodConstraint("POST") }
+ // a) Route: template = "/{foo}", Constraints = { httpMethod = new HttpMethodRouteConstraint("GET") }
+ // b) Route: template = "/{foo}", Constraints = { httpMethod = new HttpMethodRouteConstraint("POST") }
//
// A user might know ahead of time that a URI he/she is generating might be used with a particular HTTP
// method. If a URI will be used for an HTTP POST but we match on (a) while generating the URI, then
diff --git a/src/Microsoft.AspNet.Routing/IRouteBuilder.cs b/src/Microsoft.AspNet.Routing/IRouteBuilder.cs
index 37e1076b28..ed36d59d07 100644
--- a/src/Microsoft.AspNet.Routing/IRouteBuilder.cs
+++ b/src/Microsoft.AspNet.Routing/IRouteBuilder.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using Microsoft.AspNet.Builder;
namespace Microsoft.AspNet.Routing
{
@@ -12,6 +13,11 @@ namespace Microsoft.AspNet.Routing
///
public interface IRouteBuilder
{
+ ///
+ /// Gets the .
+ ///
+ IApplicationBuilder ApplicationBuilder { get; }
+
///
/// Gets or sets the default that is used as a handler if an
/// is added to the list of routes but does not specify its own.
diff --git a/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs b/src/Microsoft.AspNet.Routing/MapRouteRouteBuilderExtensions.cs
similarity index 97%
rename from src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs
rename to src/Microsoft.AspNet.Routing/MapRouteRouteBuilderExtensions.cs
index c825f4b4d1..21f2c26e70 100644
--- a/src/Microsoft.AspNet.Routing/RouteBuilderExtensions.cs
+++ b/src/Microsoft.AspNet.Routing/MapRouteRouteBuilderExtensions.cs
@@ -2,9 +2,7 @@
// 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.AspNet.Routing;
-using Microsoft.AspNet.Routing.Template;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNet.Builder
@@ -12,7 +10,7 @@ namespace Microsoft.AspNet.Builder
///
/// Provides extension methods for to add routes.
///
- public static class RouteBuilderExtensions
+ public static class MapRouteRouteBuilderExtensions
{
///
/// Adds a route to the with the specified name and template.
diff --git a/src/Microsoft.AspNet.Routing/RouteBuilder.cs b/src/Microsoft.AspNet.Routing/RouteBuilder.cs
index 666add5418..5e54be1037 100644
--- a/src/Microsoft.AspNet.Routing/RouteBuilder.cs
+++ b/src/Microsoft.AspNet.Routing/RouteBuilder.cs
@@ -3,19 +3,35 @@
using System;
using System.Collections.Generic;
+using Microsoft.AspNet.Builder;
namespace Microsoft.AspNet.Routing
{
public class RouteBuilder : IRouteBuilder
{
- public RouteBuilder()
+ public RouteBuilder(IApplicationBuilder applicationBuilder)
+ : this(applicationBuilder, defaultHandler: null)
{
+ }
+
+ public RouteBuilder(IApplicationBuilder applicationBuilder, IRouter defaultHandler)
+ {
+ if (applicationBuilder == null)
+ {
+ throw new ArgumentNullException(nameof(applicationBuilder));
+ }
+
+ ApplicationBuilder = applicationBuilder;
+ ServiceProvider = applicationBuilder.ApplicationServices;
+
Routes = new List();
}
+ public IApplicationBuilder ApplicationBuilder { get; }
+
public IRouter DefaultHandler { get; set; }
- public IServiceProvider ServiceProvider { get; set; }
+ public IServiceProvider ServiceProvider { get; }
public IList Routes { get; }
diff --git a/test/Microsoft.AspNet.Routing.Extensions.Tests/Microsoft.AspNet.Routing.Extensions.Tests.xproj b/test/Microsoft.AspNet.Routing.Extensions.Tests/Microsoft.AspNet.Routing.Extensions.Tests.xproj
new file mode 100644
index 0000000000..b3b50c729b
--- /dev/null
+++ b/test/Microsoft.AspNet.Routing.Extensions.Tests/Microsoft.AspNet.Routing.Extensions.Tests.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ fd0151b4-7153-49a8-9d90-62a252420230
+ Microsoft.AspNet.Routing.Extensions.Tests
+ ..\..\artifacts\obj\$(MSBuildProjectName)
+ ..\..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Microsoft.AspNet.Routing.Extensions.Tests/RequestDelegateRouteBuilderExtensionsTest.cs b/test/Microsoft.AspNet.Routing.Extensions.Tests/RequestDelegateRouteBuilderExtensionsTest.cs
new file mode 100644
index 0000000000..de8622ffe1
--- /dev/null
+++ b/test/Microsoft.AspNet.Routing.Extensions.Tests/RequestDelegateRouteBuilderExtensionsTest.cs
@@ -0,0 +1,157 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNet.Http;
+using Microsoft.AspNet.Http.Internal;
+using Microsoft.AspNet.Routing;
+using Microsoft.Extensions.DependencyInjection;
+using Moq;
+using Xunit;
+
+namespace Microsoft.AspNet.Builder
+{
+ // These are really more like integration tests. They verify that these extensions
+ // add routes that behave as advertised.
+ public class RequestDelegateRouteBuilderExtensionsTest
+ {
+ private static readonly RequestDelegate NullHandler = (c) => Task.FromResult(0);
+
+ public static TheoryData, Action> MatchingActions
+ {
+ get
+ {
+ return new TheoryData, Action>()
+ {
+ { b => { b.MapRoute("api/{id}", NullHandler); }, null },
+ { b => { b.MapRoute("api/{id}", app => { }); }, null },
+
+ { b => { b.MapDelete("api/{id}", NullHandler); }, c => { c.Request.Method = "DELETE"; } },
+ { b => { b.MapDelete("api/{id}", app => { }); }, c => { c.Request.Method = "DELETE"; } },
+ { b => { b.MapGet("api/{id}", NullHandler); }, c => { c.Request.Method = "GET"; } },
+ { b => { b.MapGet("api/{id}", app => { }); }, c => { c.Request.Method = "GET"; } },
+ { b => { b.MapPost("api/{id}", NullHandler); }, c => { c.Request.Method = "POST"; } },
+ { b => { b.MapPost("api/{id}", app => { }); }, c => { c.Request.Method = "POST"; } },
+ { b => { b.MapPut("api/{id}", NullHandler); }, c => { c.Request.Method = "PUT"; } },
+ { b => { b.MapPut("api/{id}", app => { }); }, c => { c.Request.Method = "PUT"; } },
+
+ { b => { b.MapVerb("PUT", "api/{id}", NullHandler); }, c => { c.Request.Method = "PUT"; } },
+ { b => { b.MapVerb("PUT", "api/{id}", app => { }); }, c => { c.Request.Method = "PUT"; } },
+ };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(MatchingActions))]
+ public async Task Map_MatchesRequest(
+ Action routeSetup,
+ Action requestSetup)
+ {
+ // Arrange
+ var services = CreateServices();
+
+ var context = CreateRouteContext(services);
+ context.HttpContext.Request.Path = new PathString("/api/5");
+ requestSetup?.Invoke(context.HttpContext);
+
+ var builder = CreateRouteBuilder(services);
+ routeSetup(builder);
+ var route = builder.Build();
+
+ // Act
+ await route.RouteAsync(context);
+
+ // Assert
+ Assert.Same(NullHandler, context.Handler);
+ }
+
+ public static TheoryData, Action> NonmatchingActions
+ {
+ get
+ {
+ return new TheoryData, Action>()
+ {
+ { b => { b.MapRoute("api/{id}/extra", NullHandler); }, null },
+ { b => { b.MapRoute("api/{id}/extra", app => { }); }, null },
+
+ { b => { b.MapDelete("api/{id}", NullHandler); }, c => { c.Request.Method = "GET"; } },
+ { b => { b.MapDelete("api/{id}", app => { }); }, c => { c.Request.Method = "PUT"; } },
+ { b => { b.MapDelete("api/{id}/extra", NullHandler); }, c => { c.Request.Method = "DELETE"; } },
+ { b => { b.MapDelete("api/{id}/extra", app => { }); }, c => { c.Request.Method = "DELETE"; } },
+ { b => { b.MapGet("api/{id}", NullHandler); }, c => { c.Request.Method = "PUT"; } },
+ { b => { b.MapGet("api/{id}", app => { }); }, c => { c.Request.Method = "POST"; } },
+ { b => { b.MapGet("api/{id}/extra", NullHandler); }, c => { c.Request.Method = "GET"; } },
+ { b => { b.MapGet("api/{id}/extra", app => { }); }, c => { c.Request.Method = "GET"; } },
+ { b => { b.MapPost("api/{id}", NullHandler); }, c => { c.Request.Method = "MEH"; } },
+ { b => { b.MapPost("api/{id}", app => { }); }, c => { c.Request.Method = "DELETE"; } },
+ { b => { b.MapPost("api/{id}/extra", NullHandler); }, c => { c.Request.Method = "POST"; } },
+ { b => { b.MapPost("api/{id}/extra", app => { }); }, c => { c.Request.Method = "POST"; } },
+ { b => { b.MapPut("api/{id}", NullHandler); }, c => { c.Request.Method = "BLEH"; } },
+ { b => { b.MapPut("api/{id}", app => { }); }, c => { c.Request.Method = "HEAD"; } },
+ { b => { b.MapPut("api/{id}/extra", NullHandler); }, c => { c.Request.Method = "PUT"; } },
+ { b => { b.MapPut("api/{id}/extra", app => { }); }, c => { c.Request.Method = "PUT"; } },
+
+ { b => { b.MapVerb("PUT", "api/{id}", NullHandler); }, c => { c.Request.Method = "POST"; } },
+ { b => { b.MapVerb("PUT", "api/{id}", app => { }); }, c => { c.Request.Method = "HEAD"; } },
+ { b => { b.MapVerb("PUT", "api/{id}/extra", NullHandler); }, c => { c.Request.Method = "PUT"; } },
+ { b => { b.MapVerb("PUT", "api/{id}/extra", app => { }); }, c => { c.Request.Method = "PUT"; } },
+ };
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(NonmatchingActions))]
+ public async Task Map_DoesNotMatchRequest(
+ Action routeSetup,
+ Action requestSetup)
+ {
+ // Arrange
+ var services = CreateServices();
+
+ var context = CreateRouteContext(services);
+ context.HttpContext.Request.Path = new PathString("/api/5");
+ requestSetup?.Invoke(context.HttpContext);
+
+ var builder = CreateRouteBuilder(services);
+ routeSetup(builder);
+ var route = builder.Build();
+
+ // Act
+ await route.RouteAsync(context);
+
+ // Assert
+ Assert.Null(context.Handler);
+ }
+
+ private static IServiceProvider CreateServices()
+ {
+ var services = new ServiceCollection();
+ services.AddRouting();
+ services.AddLogging();
+ return services.BuildServiceProvider();
+ }
+
+ private static RouteContext CreateRouteContext(IServiceProvider services)
+ {
+ var httpContext = new DefaultHttpContext();
+ httpContext.RequestServices = services;
+ return new RouteContext(httpContext);
+ }
+
+ private static IRouteBuilder CreateRouteBuilder(IServiceProvider services)
+ {
+ var applicationBuilder = new Mock();
+ applicationBuilder.SetupAllProperties();
+
+ applicationBuilder
+ .Setup(b => b.New().Build())
+ .Returns(NullHandler);
+
+ applicationBuilder.Object.ApplicationServices = services;
+
+ var routeBuilder = new RouteBuilder(applicationBuilder.Object);
+ return routeBuilder;
+ }
+ }
+}
diff --git a/test/Microsoft.AspNet.Routing.Extensions.Tests/project.json b/test/Microsoft.AspNet.Routing.Extensions.Tests/project.json
new file mode 100644
index 0000000000..deed7b001e
--- /dev/null
+++ b/test/Microsoft.AspNet.Routing.Extensions.Tests/project.json
@@ -0,0 +1,28 @@
+{
+ "compilationOptions": {
+ "warningsAsErrors": true
+ },
+ "dependencies": {
+ "Microsoft.AspNet.Http": "1.0.0-*",
+ "Microsoft.AspNet.Routing.Extensions": "1.0.0-*",
+ "Microsoft.AspNet.Testing": "1.0.0-*",
+ "Microsoft.Extensions.DependencyInjection": "1.0.0-*",
+ "Microsoft.Extensions.Logging.Testing": "1.0.0-*",
+ "xunit.runner.aspnet": "2.0.0-aspnet-*"
+ },
+ "frameworks": {
+ "dnxcore50": {
+ "dependencies": {
+ "moq.netcore": "4.4.0-beta8"
+ }
+ },
+ "dnx451": {
+ "dependencies": {
+ "Moq": "4.2.1312.1622"
+ }
+ }
+ },
+ "commands": {
+ "test": "xunit.runner.aspnet"
+ }
+}
diff --git a/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs b/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs
index 33f580518b..649351fbc6 100644
--- a/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs
+++ b/test/Microsoft.AspNet.Routing.Tests/Constraints/HttpMethodRouteConstraintTests.cs
@@ -15,7 +15,7 @@ namespace Microsoft.AspNet.Routing.Constraints
public void HttpMethodRouteConstraint_IncomingRequest_AcceptsAllowedMethods(string httpMethod)
{
// Arrange
- var constraint = new HttpRouteMethodConstraint("GET", "post");
+ var constraint = new HttpMethodRouteConstraint("GET", "post");
var httpContext = new DefaultHttpContext();
httpContext.Request.Method = httpMethod;
@@ -36,7 +36,7 @@ namespace Microsoft.AspNet.Routing.Constraints
public void HttpMethodRouteConstraint_IncomingRequest_RejectsOtherMethods(string httpMethod)
{
// Arrange
- var constraint = new HttpRouteMethodConstraint("GET", "post");
+ var constraint = new HttpMethodRouteConstraint("GET", "post");
var httpContext = new DefaultHttpContext();
httpContext.Request.Method = httpMethod;
@@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Routing.Constraints
public void HttpMethodRouteConstraint_UrlGeneration_AcceptsAllowedMethods(string httpMethod)
{
// Arrange
- var constraint = new HttpRouteMethodConstraint("GET", "post");
+ var constraint = new HttpMethodRouteConstraint("GET", "post");
var httpContext = new DefaultHttpContext();
var route = Mock.Of();
@@ -77,7 +77,7 @@ namespace Microsoft.AspNet.Routing.Constraints
public void HttpMethodRouteConstraint_UrlGeneration_RejectsOtherMethods(string httpMethod)
{
// Arrange
- var constraint = new HttpRouteMethodConstraint("GET", "post");
+ var constraint = new HttpMethodRouteConstraint("GET", "post");
var httpContext = new DefaultHttpContext();
var route = Mock.Of();
diff --git a/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs b/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs
index db1d594020..13b21d78c8 100644
--- a/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs
+++ b/test/Microsoft.AspNet.Routing.Tests/RouteTest.cs
@@ -9,8 +9,9 @@ using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing.Constraints;
using Microsoft.AspNet.Testing;
-using Microsoft.Extensions.Logging.Testing;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Testing;
using Moq;
using Xunit;
@@ -1490,15 +1491,14 @@ namespace Microsoft.AspNet.Routing
private static IRouteBuilder CreateRouteBuilder()
{
- var routeBuilder = new RouteBuilder();
+ var services = new ServiceCollection();
+ services.AddSingleton(_inlineConstraintResolver);
+ var applicationBuilder = Mock.Of();
+ applicationBuilder.ApplicationServices = services.BuildServiceProvider();
+
+ var routeBuilder = new RouteBuilder(applicationBuilder);
routeBuilder.DefaultHandler = new RouteHandler(NullHandler);
-
- var serviceProviderMock = new Mock();
- serviceProviderMock.Setup(o => o.GetService(typeof(IInlineConstraintResolver)))
- .Returns(_inlineConstraintResolver);
- routeBuilder.ServiceProvider = serviceProviderMock.Object;
-
return routeBuilder;
}
diff --git a/test/Microsoft.AspNet.Routing.Tests/TemplateParserDefaultValuesTests.cs b/test/Microsoft.AspNet.Routing.Tests/TemplateParserDefaultValuesTests.cs
index fbea8c950d..b4af45c8ad 100644
--- a/test/Microsoft.AspNet.Routing.Tests/TemplateParserDefaultValuesTests.cs
+++ b/test/Microsoft.AspNet.Routing.Tests/TemplateParserDefaultValuesTests.cs
@@ -96,26 +96,28 @@ namespace Microsoft.AspNet.Routing.Tests
var routeBuilder = CreateRouteBuilder();
// Act & Assert
- var ex = Assert.Throws(
- () => routeBuilder.MapRoute("mockName",
- "{controller}/{action}/{id:int=12?}",
- defaults: new { id = 13 },
- constraints: null));
+ var ex = Assert.Throws(() =>
+ {
+ routeBuilder.MapRoute(
+ "mockName",
+ "{controller}/{action}/{id:int=12?}",
+ defaults: new { id = 13 },
+ constraints: null);
+ });
Assert.Equal(message, ex.Message);
}
private static IRouteBuilder CreateRouteBuilder()
{
- var routeBuilder = new RouteBuilder();
+ var services = new ServiceCollection();
+ services.AddSingleton(_inlineConstraintResolver);
- routeBuilder.DefaultHandler = new Mock().Object;
-
- var serviceProviderMock = new Mock();
- serviceProviderMock.Setup(o => o.GetService(typeof(IInlineConstraintResolver)))
- .Returns(_inlineConstraintResolver);
- routeBuilder.ServiceProvider = serviceProviderMock.Object;
+ var applicationBuilder = Mock.Of();
+ applicationBuilder.ApplicationServices = services.BuildServiceProvider();
+ var routeBuilder = new RouteBuilder(applicationBuilder);
+ routeBuilder.DefaultHandler = Mock.Of();
return routeBuilder;
}