Add extension methods for using routing with Middleware

This commit is contained in:
Ryan Nowak 2015-12-11 19:16:06 -08:00
parent cc501bc025
commit cb39589864
19 changed files with 584 additions and 53 deletions

View File

@ -10,6 +10,7 @@
],
"packages": {
"Microsoft.AspNet.Routing.Abstractions": { },
"Microsoft.AspNet.Routing.Extensions": { },
"Microsoft.AspNet.Routing": { }
}
},

View File

@ -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

View File

@ -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());
}
}
}

View File

@ -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": { }
}
}

View File

@ -1 +0,0 @@
RoutingSample.Web

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>579c3fd2-dffa-4b64-bfc3-130c11f3568f</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Routing.Extensions</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -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")]

View File

@ -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
{
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> for the given <paramref name="template"/>, and
/// <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
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;
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> for the given <paramref name="template"/>, and
/// <paramref name="action"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapRoute(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
{
var nested = builder.ApplicationBuilder.New();
action(nested);
return builder.MapRoute(template, nested.Build());
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapDelete(this IRouteBuilder builder, string template, RequestDelegate handler)
{
return builder.MapVerb("DELETE", template, handler);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="action"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapDelete(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
{
return builder.MapVerb("DELETE", template, action);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapGet(this IRouteBuilder builder, string template, RequestDelegate handler)
{
return builder.MapVerb("GET", template, handler);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="action"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapGet(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
{
return builder.MapVerb("GET", template, action);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapPost(this IRouteBuilder builder, string template, RequestDelegate handler)
{
return builder.MapVerb("POST", template, handler);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="action"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapPost(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
{
return builder.MapVerb("POST", template, action);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapPut(this IRouteBuilder builder, string template, RequestDelegate handler)
{
return builder.MapVerb("PUT", template, handler);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP DELETE requests for the given
/// <paramref name="template"/>, and <paramref name="action"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="template">The route template.</param>
/// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapPut(this IRouteBuilder builder, string template, Action<IApplicationBuilder> action)
{
return builder.MapVerb("PUT", template, action);
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP requests for the given
/// <paramref name="verb"/>, <paramref name="template"/>, and <paramref name="handler"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="verb">The HTTP verb allowed by the route.</param>
/// <param name="template">The route template.</param>
/// <param name="handler">The <see cref="RequestDelegate"/> route handler.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
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;
}
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> that only matches HTTP requests for the given
/// <paramref name="verb"/>, <paramref name="template"/>, and <paramref name="action"/>.
/// </summary>
/// <param name="builder">The <see cref="IRouteBuilder"/>.</param>
/// <param name="verb">The HTTP verb allowed by the route.</param>
/// <param name="template">The route template.</param>
/// <param name="action">The action to apply to the <see cref="IApplicationBuilder"/>.</param>
/// <returns>A reference to the <paramref name="builder"/> after this operation has completed.</returns>
public static IRouteBuilder MapVerb(
this IRouteBuilder builder,
string verb,
string template,
Action<IApplicationBuilder> 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<IInlineConstraintResolver>();
}
}
}

View File

@ -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": { }
}
}

View File

@ -11,14 +11,14 @@ namespace Microsoft.AspNet.Routing.Constraints
/// <summary>
/// Constrains the HTTP method of request or a route.
/// </summary>
public class HttpRouteMethodConstraint : IRouteConstraint
public class HttpMethodRouteConstraint : IRouteConstraint
{
/// <summary>
/// Creates a new <see cref="HttpRouteMethodConstraint"/> that accepts the HTTP methods specified
/// Creates a new <see cref="HttpMethodRouteConstraint"/> that accepts the HTTP methods specified
/// by <paramref name="allowedMethods"/>.
/// </summary>
/// <param name="allowedMethods">The allowed HTTP methods.</param>
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

View File

@ -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
/// </summary>
public interface IRouteBuilder
{
/// <summary>
/// Gets the <see cref="IApplicationBuilder"/>.
/// </summary>
IApplicationBuilder ApplicationBuilder { get; }
/// <summary>
/// Gets or sets the default <see cref="IRouter"/> that is used as a handler if an <see cref="IRouter"/>
/// is added to the list of routes but does not specify its own.

View File

@ -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
/// <summary>
/// Provides extension methods for <see cref="IRouteBuilder"/> to add routes.
/// </summary>
public static class RouteBuilderExtensions
public static class MapRouteRouteBuilderExtensions
{
/// <summary>
/// Adds a route to the <see cref="IRouteBuilder"/> with the specified name and template.

View File

@ -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<IRouter>();
}
public IApplicationBuilder ApplicationBuilder { get; }
public IRouter DefaultHandler { get; set; }
public IServiceProvider ServiceProvider { get; set; }
public IServiceProvider ServiceProvider { get; }
public IList<IRouter> Routes { get; }

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>fd0151b4-7153-49a8-9d90-62a252420230</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Routing.Extensions.Tests</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -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<IRouteBuilder>, Action<HttpContext>> MatchingActions
{
get
{
return new TheoryData<Action<IRouteBuilder>, Action<HttpContext>>()
{
{ 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<IRouteBuilder> routeSetup,
Action<HttpContext> 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<IRouteBuilder>, Action<HttpContext>> NonmatchingActions
{
get
{
return new TheoryData<Action<IRouteBuilder>, Action<HttpContext>>()
{
{ 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<IRouteBuilder> routeSetup,
Action<HttpContext> 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<IApplicationBuilder>();
applicationBuilder.SetupAllProperties();
applicationBuilder
.Setup(b => b.New().Build())
.Returns(NullHandler);
applicationBuilder.Object.ApplicationServices = services;
var routeBuilder = new RouteBuilder(applicationBuilder.Object);
return routeBuilder;
}
}
}

View File

@ -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"
}
}

View File

@ -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<IRouter>();
@ -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<IRouter>();

View File

@ -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<IInlineConstraintResolver>(_inlineConstraintResolver);
var applicationBuilder = Mock.Of<IApplicationBuilder>();
applicationBuilder.ApplicationServices = services.BuildServiceProvider();
var routeBuilder = new RouteBuilder(applicationBuilder);
routeBuilder.DefaultHandler = new RouteHandler(NullHandler);
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(o => o.GetService(typeof(IInlineConstraintResolver)))
.Returns(_inlineConstraintResolver);
routeBuilder.ServiceProvider = serviceProviderMock.Object;
return routeBuilder;
}

View File

@ -96,26 +96,28 @@ namespace Microsoft.AspNet.Routing.Tests
var routeBuilder = CreateRouteBuilder();
// Act & Assert
var ex = Assert.Throws<ArgumentException>(
() => routeBuilder.MapRoute("mockName",
"{controller}/{action}/{id:int=12?}",
defaults: new { id = 13 },
constraints: null));
var ex = Assert.Throws<ArgumentException>(() =>
{
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<IInlineConstraintResolver>(_inlineConstraintResolver);
routeBuilder.DefaultHandler = new Mock<IRouter>().Object;
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(o => o.GetService(typeof(IInlineConstraintResolver)))
.Returns(_inlineConstraintResolver);
routeBuilder.ServiceProvider = serviceProviderMock.Object;
var applicationBuilder = Mock.Of<IApplicationBuilder>();
applicationBuilder.ApplicationServices = services.BuildServiceProvider();
var routeBuilder = new RouteBuilder(applicationBuilder);
routeBuilder.DefaultHandler = Mock.Of<IRouter>();
return routeBuilder;
}