Revert "Getting routing prototype into history"
We're not using the prototype as a base, just want to to be in the history
so we can easily refer to it.
This reverts commit 4183bc98be.
This commit is contained in:
parent
4183bc98be
commit
c0660f347a
|
|
@ -1,63 +0,0 @@
|
|||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
43
Routing.sln
43
Routing.sln
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Routing.net45", "src\Microsoft.AspNet.Routing\Microsoft.AspNet.Routing.net45.csproj", "{BD60E294-D97A-46CE-A6F0-2A293989B56B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{949A5859-ACBA-4687-B393-644BCF32C1D8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Routing.k10", "src\Microsoft.AspNet.Routing\Microsoft.AspNet.Routing.k10.csproj", "{4463D373-7BAA-42DC-803E-C4B2B8D3A2F4}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoutingSample.net45", "samples\RoutingSample\RoutingSample.net45.csproj", "{6552385C-3FB0-40A0-A29B-2B5A5C411621}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{2B8B4E94-8C98-4959-9116-4BAD8FF69468}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{BD60E294-D97A-46CE-A6F0-2A293989B56B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BD60E294-D97A-46CE-A6F0-2A293989B56B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BD60E294-D97A-46CE-A6F0-2A293989B56B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BD60E294-D97A-46CE-A6F0-2A293989B56B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4463D373-7BAA-42DC-803E-C4B2B8D3A2F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4463D373-7BAA-42DC-803E-C4B2B8D3A2F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4463D373-7BAA-42DC-803E-C4B2B8D3A2F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4463D373-7BAA-42DC-803E-C4B2B8D3A2F4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6552385C-3FB0-40A0-A29B-2B5A5C411621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6552385C-3FB0-40A0-A29B-2B5A5C411621}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6552385C-3FB0-40A0-A29B-2B5A5C411621}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6552385C-3FB0-40A0-A29B-2B5A5C411621}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{BD60E294-D97A-46CE-A6F0-2A293989B56B} = {949A5859-ACBA-4687-B393-644BCF32C1D8}
|
||||
{4463D373-7BAA-42DC-803E-C4B2B8D3A2F4} = {949A5859-ACBA-4687-B393-644BCF32C1D8}
|
||||
{6552385C-3FB0-40A0-A29B-2B5A5C411621} = {2B8B4E94-8C98-4959-9116-4BAD8FF69468}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
using System;
|
||||
using Microsoft.Owin.Hosting;
|
||||
|
||||
namespace RoutingSample
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
string url = "http://localhost:30000";
|
||||
using (WebApp.Start<Startup>(url))
|
||||
{
|
||||
Console.WriteLine("Listening on: {0}", url);
|
||||
Console.WriteLine("Press ENTER to exit.");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Routing.HttpMethod;
|
||||
using Microsoft.AspNet.Routing.Lambda;
|
||||
using Microsoft.AspNet.Routing.Legacy;
|
||||
using Microsoft.AspNet.Routing.Owin;
|
||||
using Microsoft.AspNet.Routing.Template;
|
||||
using Microsoft.AspNet.Routing.Tree;
|
||||
using Owin;
|
||||
|
||||
namespace RoutingSample
|
||||
{
|
||||
internal class Startup
|
||||
{
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
// Configuring the router places it in the OWIN pipeline and retuns an IRouteBuilder which is used
|
||||
// To create routes - all routes are directed to nested pipelines.
|
||||
var router = app.UseRouter();
|
||||
|
||||
|
||||
// At the simplest level - we can support microframework style routing.
|
||||
//
|
||||
// This route matches a prefix of the request path, and a specific HTTP method.
|
||||
router.Get("1/echo", async (context) =>
|
||||
{
|
||||
string url = (string)context["owin.RequestPath"];
|
||||
await WriteAsync(context, url);
|
||||
});
|
||||
|
||||
|
||||
// This route takes a lambda, and can apply arbitrary criteria for routing without needing to couple
|
||||
// to an object model.
|
||||
router.On(context => ((string)context["owin.RequestPath"]).StartsWith("2"), async (context) =>
|
||||
{
|
||||
string url = (string)context["owin.RequestPath"];
|
||||
await WriteAsync(context, url);
|
||||
});
|
||||
|
||||
|
||||
// The return value is an IRouteEndpoint - extension method friendly for adding more routes and different
|
||||
// route types.
|
||||
//
|
||||
// All of these routes go to the same delegate.
|
||||
router.Get("3/Store", async (context) =>
|
||||
{
|
||||
string method = (string)context["owin.RequestMethod"];
|
||||
await WriteAsync(context, method);
|
||||
})
|
||||
.Post("3/Store/Checkout")
|
||||
.On(context => ((string)context["owin.RequestPath"]).StartsWith("3/api"));
|
||||
|
||||
|
||||
// Routing to a middleware using IAppBuilder -- allowing routing to a more complex pipeline.
|
||||
router.ForApp((builder) => builder.Use(async (context, next) =>
|
||||
{
|
||||
await context.Response.WriteAsync("Hello, World!");
|
||||
}))
|
||||
.Get("4/Hello")
|
||||
.Post("4/Hello/World");
|
||||
|
||||
|
||||
// Nested Router
|
||||
router.ForApp((builder) =>
|
||||
{
|
||||
var nested = builder.UseRouter();
|
||||
|
||||
nested.Get(async (context) => await WriteAsync(context, "Get"));
|
||||
nested.Post(async (context) => await WriteAsync(context, "Post"));
|
||||
})
|
||||
.Get("5/Store");
|
||||
|
||||
|
||||
|
||||
// MVC/WebAPI Stuff below - using 'tradition' template routes.
|
||||
|
||||
|
||||
// Routing with parameter capturing - the route data is stored in the owin context
|
||||
router.ForApp((builder) => builder.Use(async (context, next) =>
|
||||
{
|
||||
string controller = (string)context.Environment.GetRouteMatchValues()["controller"];
|
||||
await context.Response.WriteAsync(controller);
|
||||
|
||||
}))
|
||||
.AddTemplateRoute("6/api/{controller}", new HttpRouteValueDictionary(new { controller = "Home" }));
|
||||
|
||||
|
||||
// Routing with data tokens - these are added to the context when a route matches
|
||||
// This technique can be used for MVC/Web API to perform action selection as part of routing
|
||||
router.ForApp((builder) => builder.Use(async (context, next) =>
|
||||
{
|
||||
string stringValue = (string)context.Environment["myapp_StringValue"];
|
||||
await context.Response.WriteAsync(stringValue);
|
||||
|
||||
}))
|
||||
.AddTemplateRoute("7", null, null, data: new HttpRouteValueDictionary(new { myapp_StringValue = "cool" }));
|
||||
|
||||
|
||||
// The route engine can be provided as a parameter to the app builder function so that it can be
|
||||
// captured and used inside of the application.
|
||||
//
|
||||
// It's also provided as part of the owin context on a routed request for apps that would prefer
|
||||
// a stateless style.
|
||||
router.ForApp((builder, engine) => builder.Use(async (context, next) =>
|
||||
{
|
||||
if (Object.Equals(engine, context.Environment.GetRouteEngine()))
|
||||
{
|
||||
await context.Response.WriteAsync(engine.GetType().ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
await next();
|
||||
}
|
||||
}))
|
||||
.AddTemplateRoute("8");
|
||||
|
||||
|
||||
// Generating a link by name
|
||||
router.ForApp((builder, engine) => builder.Use(async (context, next) =>
|
||||
{
|
||||
string url = engine.GetUrl("ByName", context.Environment, new HttpRouteValueDictionary(new { })).Url;
|
||||
await context.Response.WriteAsync(url);
|
||||
}))
|
||||
.AddTemplateRoute("ByName", "9/{value1}", new HttpRouteValueDictionary(new { value1 = "Cool" }));
|
||||
|
||||
|
||||
// Tree Routing
|
||||
var tree = router.AddTreeRoute();
|
||||
tree.Path("10/api").Parameter("controller").Endpoint(router.ForApp((builder) => builder.Use(async (context, next) =>
|
||||
{
|
||||
string url = context.Request.Uri.PathAndQuery;
|
||||
await context.Response.WriteAsync(url);
|
||||
})));
|
||||
|
||||
|
||||
tree.Build();
|
||||
}
|
||||
|
||||
private static Task WriteAsync(IDictionary<string, object> context, string value)
|
||||
{
|
||||
var response = (Stream)context["owin.ResponseBody"];
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(value);
|
||||
return response.WriteAsync(bytes, 0, bytes.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"version": "0.1-alpha-*",
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Routing" : ""
|
||||
},
|
||||
"configurations": {
|
||||
"net45": {
|
||||
"dependencies": {
|
||||
"Owin": "1.0",
|
||||
"Microsoft.Owin.Diagnostics": "2.1.0",
|
||||
"Microsoft.Owin.Host.HttpListener": "2.1.0",
|
||||
"Microsoft.Owin.Hosting": "2.1.0",
|
||||
"Microsoft.Owin.SelfHost": "2.1.0",
|
||||
"Microsoft.Owin": "2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class BoundRoute
|
||||
{
|
||||
public BoundRoute(string url, IDictionary<string, object> values)
|
||||
{
|
||||
this.Url = url;
|
||||
this.Values = values;
|
||||
}
|
||||
|
||||
public string Url
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Values
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public static class OwinExtensions
|
||||
{
|
||||
public static string EngineKey = "routing.Engine";
|
||||
public static string MatchValuesKey = "routing.Values";
|
||||
|
||||
public static IRouteEngine GetRouteEngine(this IDictionary<string, object> context)
|
||||
{
|
||||
object obj;
|
||||
if (context.TryGetValue(EngineKey, out obj))
|
||||
{
|
||||
return obj as IRouteEngine;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void SetRouteEngine(this IDictionary<string, object> context, IRouteEngine value)
|
||||
{
|
||||
context[EngineKey] = value;
|
||||
}
|
||||
|
||||
public static IDictionary<string, object> GetRouteMatchValues(this IDictionary<string, object> context)
|
||||
{
|
||||
object obj;
|
||||
if (context.TryGetValue(MatchValuesKey, out obj))
|
||||
{
|
||||
return obj as IDictionary<string, object>;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void SetRouteMatchValues(this IDictionary<string, object> context, IDictionary<string, object> values)
|
||||
{
|
||||
context[MatchValuesKey] = values;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.HttpMethod
|
||||
{
|
||||
public class HttpMethodRoute : PrefixRoute
|
||||
{
|
||||
public HttpMethodRoute(IRouteEndpoint endpoint, string prefix, string method)
|
||||
: base(endpoint, prefix)
|
||||
{
|
||||
this.Method = method;
|
||||
}
|
||||
|
||||
private string Method
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public override RouteMatch GetMatch(RoutingContext context)
|
||||
{
|
||||
if (String.Equals(context.RequestMethod, this.Method, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return base.GetMatch(context);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Routing.Template;
|
||||
|
||||
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.HttpMethod
|
||||
{
|
||||
public static class HttpMethodRouteExtensions
|
||||
{
|
||||
public static IRouteEndpoint Get(this IRouteEndpoint endpoint)
|
||||
{
|
||||
endpoint.AddRoute(null, new HttpMethodRoute(endpoint, null, "GET"));
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Get(this IRouteBuilder routeBuilder, AppFunc handler)
|
||||
{
|
||||
var endpoint = routeBuilder.ForApp((next) => handler);
|
||||
return endpoint.Get();
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Get(this IRouteEndpoint endpoint, string prefix)
|
||||
{
|
||||
endpoint.AddRoute(null, new HttpMethodRoute(endpoint, prefix, "GET"));
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Get(this IRouteBuilder routeBuilder, string prefix, AppFunc handler)
|
||||
{
|
||||
var endpoint = routeBuilder.ForApp((next) => handler);
|
||||
return endpoint.Get(prefix);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Post(this IRouteEndpoint endpoint)
|
||||
{
|
||||
endpoint.AddRoute(null, new HttpMethodRoute(endpoint, null, "POST"));
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Post(this IRouteBuilder routeBuilder, AppFunc handler)
|
||||
{
|
||||
var endpoint = routeBuilder.ForApp((next) => handler);
|
||||
return endpoint.Post();
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Post(this IRouteEndpoint endpoint, string prefix)
|
||||
{
|
||||
endpoint.AddRoute(null, new HttpMethodRoute(endpoint, prefix, "POST"));
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static IRouteEndpoint Post(this IRouteBuilder routeBuilder, string prefix, AppFunc handler)
|
||||
{
|
||||
var endpoint = routeBuilder.ForApp((next) => handler);
|
||||
return endpoint.Post(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IConstraint
|
||||
{
|
||||
bool MatchInbound(RoutingContext context, IDictionary<string, object> values, object value);
|
||||
|
||||
bool MatchOutbound(RouteBindingContext context, IDictionary<string, object> values, object value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IRoute
|
||||
{
|
||||
BoundRoute Bind(RouteBindingContext context);
|
||||
|
||||
RouteMatch GetMatch(RoutingContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
#if NET45
|
||||
using Owin;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IRouteBuilder
|
||||
{
|
||||
#if NET45
|
||||
IAppBuilder AppBuilder
|
||||
{
|
||||
get;
|
||||
}
|
||||
#endif
|
||||
IRouteEngine Engine
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
IRouteEndpoint ForApp(Func<Func<IDictionary<string, object>, Task>> handlerFactory);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IRouteEndpoint
|
||||
{
|
||||
Func<IDictionary<string, object>, Task> AppFunc
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
IRouteEndpoint AddRoute(string name, IRoute route);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public interface IRouteEngine
|
||||
{
|
||||
RouteMatch GetMatch(IDictionary<string, object> context);
|
||||
|
||||
BoundRoute GetUrl(string routeName, IDictionary<string, object> context, IDictionary<string, object> values);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Lambda
|
||||
{
|
||||
public class LambdaRoute : IRoute
|
||||
{
|
||||
public LambdaRoute(IRouteEndpoint endpoint, Func<IDictionary<string, object>, bool> condition)
|
||||
{
|
||||
this.Endpoint = endpoint;
|
||||
this.Condition = condition;
|
||||
}
|
||||
|
||||
private Func<IDictionary<string, object>, bool> Condition
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private IRouteEndpoint Endpoint
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public BoundRoute Bind(RouteBindingContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public RouteMatch GetMatch(RoutingContext context)
|
||||
{
|
||||
if (Condition(context.Context))
|
||||
{
|
||||
return new RouteMatch(this.Endpoint.AppFunc);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Lambda
|
||||
{
|
||||
public static class LambdaRouteExtensions
|
||||
{
|
||||
public static IRouteEndpoint On(this IRouteEndpoint endpoint, Func<IDictionary<string, object>, bool> condition)
|
||||
{
|
||||
endpoint.AddRoute(null, new LambdaRoute(endpoint, condition));
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public static IRouteEndpoint On(this IRouteBuilder routeBuilder, Func<IDictionary<string, object>, bool> condition, AppFunc handler)
|
||||
{
|
||||
var endpoint = routeBuilder.ForApp(handler);
|
||||
return endpoint.On(condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Legacy
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a URI generated from a <see cref="HttpParsedRoute"/>.
|
||||
/// </summary>
|
||||
internal class BoundRouteTemplate
|
||||
{
|
||||
public string BoundTemplate { get; set; }
|
||||
|
||||
public IDictionary<string, object> Values { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,821 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Legacy
|
||||
{
|
||||
internal sealed class HttpParsedRoute
|
||||
{
|
||||
public HttpParsedRoute(List<PathSegment> pathSegments)
|
||||
{
|
||||
Contract.Assert(pathSegments != null);
|
||||
PathSegments = pathSegments;
|
||||
|
||||
this.ParameterSegments = new List<PathParameterSubsegment>();
|
||||
|
||||
for (int i = 0; i < this.PathSegments.Count; i++)
|
||||
{
|
||||
var segment = this.PathSegments[i] as PathContentSegment;
|
||||
if (segment != null)
|
||||
{
|
||||
for (int j = 0; j < segment.Subsegments.Count; j++)
|
||||
{
|
||||
var subsegment = segment.Subsegments[j] as PathParameterSubsegment;
|
||||
if (subsegment != null)
|
||||
{
|
||||
this.ParameterSegments.Add(subsegment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<PathSegment> PathSegments { get; private set; }
|
||||
|
||||
public List<PathParameterSubsegment> ParameterSegments { get; private set; }
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Not changing original algorithm")]
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode", Justification = "Not changing original algorithm")]
|
||||
public BoundRouteTemplate Bind(RouteBindingContext context, IDictionary<string, object> defaults)
|
||||
{
|
||||
IDictionary<string, object> currentValues = context.AmbientValues;
|
||||
IDictionary<string, object> values = context.Values;
|
||||
|
||||
IDictionary<string, object> constraints = null;
|
||||
|
||||
if (currentValues == null)
|
||||
{
|
||||
currentValues = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
values = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (defaults == null)
|
||||
{
|
||||
defaults = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
// The set of values we should be using when generating the URI in this route
|
||||
Dictionary<string, object> acceptedValues = new Dictionary<string, object>();
|
||||
|
||||
// Keep track of which new values have been used
|
||||
HashSet<string> unusedNewValues = new HashSet<string>(values.Keys, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Step 1: Get the list of values we're going to try to use to match and generate this URI
|
||||
|
||||
// Find out which entries in the URI are valid for the URI we want to generate.
|
||||
// If the URI had ordered parameters a="1", b="2", c="3" and the new values
|
||||
// specified that b="9", then we need to invalidate everything after it. The new
|
||||
// values should then be a="1", b="9", c=<no value>.
|
||||
for (int i = 0; i < this.ParameterSegments.Count; i++)
|
||||
{
|
||||
PathParameterSubsegment parameter = this.ParameterSegments[i];
|
||||
|
||||
// If it's a parameter subsegment, examine the current value to see if it matches the new value
|
||||
string parameterName = parameter.ParameterName;
|
||||
|
||||
object newParameterValue;
|
||||
bool hasNewParameterValue = values.TryGetValue(parameterName, out newParameterValue);
|
||||
if (hasNewParameterValue)
|
||||
{
|
||||
unusedNewValues.Remove(parameterName);
|
||||
}
|
||||
|
||||
object currentParameterValue;
|
||||
bool hasCurrentParameterValue = currentValues.TryGetValue(parameterName, out currentParameterValue);
|
||||
|
||||
if (hasNewParameterValue && hasCurrentParameterValue)
|
||||
{
|
||||
if (!RoutePartsEqual(currentParameterValue, newParameterValue))
|
||||
{
|
||||
// Stop copying current values when we find one that doesn't match
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the parameter is a match, add it to the list of values we will use for URI generation
|
||||
if (hasNewParameterValue)
|
||||
{
|
||||
if (IsRoutePartNonEmpty(newParameterValue))
|
||||
{
|
||||
acceptedValues.Add(parameterName, newParameterValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hasCurrentParameterValue)
|
||||
{
|
||||
acceptedValues.Add(parameterName, currentParameterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add all remaining new values to the list of values we will use for URI generation
|
||||
foreach (var newValue in values)
|
||||
{
|
||||
if (IsRoutePartNonEmpty(newValue.Value))
|
||||
{
|
||||
if (!acceptedValues.ContainsKey(newValue.Key))
|
||||
{
|
||||
acceptedValues.Add(newValue.Key, newValue.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all current values that aren't in the URI at all
|
||||
foreach (var currentValue in currentValues)
|
||||
{
|
||||
string parameterName = currentValue.Key;
|
||||
if (!acceptedValues.ContainsKey(parameterName))
|
||||
{
|
||||
PathParameterSubsegment parameterSubsegment = GetParameterSubsegment(PathSegments, parameterName);
|
||||
if (parameterSubsegment == null)
|
||||
{
|
||||
acceptedValues.Add(parameterName, currentValue.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all remaining default values from the route to the list of values we will use for URI generation
|
||||
for (int i = 0; i < this.ParameterSegments.Count; i++)
|
||||
{
|
||||
PathParameterSubsegment parameter = this.ParameterSegments[i];
|
||||
if (!acceptedValues.ContainsKey(parameter.ParameterName))
|
||||
{
|
||||
object defaultValue;
|
||||
if (!IsParameterRequired(parameter, defaults, out defaultValue))
|
||||
{
|
||||
// Add the default value only if there isn't already a new value for it and
|
||||
// only if it actually has a default value, which we determine based on whether
|
||||
// the parameter value is required.
|
||||
acceptedValues.Add(parameter.ParameterName, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All required parameters in this URI must have values from somewhere (i.e. the accepted values)
|
||||
bool hasAllRequiredValues = true;
|
||||
for (int i = 0; i < this.ParameterSegments.Count; i++)
|
||||
{
|
||||
PathParameterSubsegment parameter = this.ParameterSegments[i];
|
||||
|
||||
object defaultValue;
|
||||
if (IsParameterRequired(parameter, defaults, out defaultValue))
|
||||
{
|
||||
if (!acceptedValues.ContainsKey(parameter.ParameterName))
|
||||
{
|
||||
// If the route parameter value is required that means there's
|
||||
// no default value, so if there wasn't a new value for it
|
||||
// either, this route won't match.
|
||||
hasAllRequiredValues = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAllRequiredValues)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// All other default values must match if they are explicitly defined in the new values
|
||||
Dictionary<string, object> otherDefaultValues = new Dictionary<string, object>(defaults, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
for (int i = 0; i < this.ParameterSegments.Count; i++)
|
||||
{
|
||||
PathParameterSubsegment parameter = this.ParameterSegments[i];
|
||||
otherDefaultValues.Remove(parameter.ParameterName);
|
||||
}
|
||||
|
||||
foreach (var defaultValue in otherDefaultValues)
|
||||
{
|
||||
object value;
|
||||
if (values.TryGetValue(defaultValue.Key, out value))
|
||||
{
|
||||
unusedNewValues.Remove(defaultValue.Key);
|
||||
if (!RoutePartsEqual(value, defaultValue.Value))
|
||||
{
|
||||
// If there is a non-parameterized value in the route and there is a
|
||||
// new value for it and it doesn't match, this route won't match.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: If the route is a match generate the appropriate URI
|
||||
|
||||
StringBuilder uri = new StringBuilder();
|
||||
StringBuilder pendingParts = new StringBuilder();
|
||||
|
||||
bool pendingPartsAreAllSafe = false;
|
||||
bool blockAllUriAppends = false;
|
||||
|
||||
for (int i = 0; i < PathSegments.Count; i++)
|
||||
{
|
||||
PathSegment pathSegment = PathSegments[i]; // parsedRouteUriPart
|
||||
|
||||
if (pathSegment is PathSeparatorSegment)
|
||||
{
|
||||
if (pendingPartsAreAllSafe)
|
||||
{
|
||||
// Accept
|
||||
if (pendingParts.Length > 0)
|
||||
{
|
||||
if (blockAllUriAppends)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Append any pending literals to the URI
|
||||
uri.Append(pendingParts.ToString());
|
||||
pendingParts.Length = 0;
|
||||
}
|
||||
}
|
||||
pendingPartsAreAllSafe = false;
|
||||
|
||||
// Guard against appending multiple separators for empty segments
|
||||
if (pendingParts.Length > 0 && pendingParts[pendingParts.Length - 1] == '/')
|
||||
{
|
||||
// Dev10 676725: Route should not be matched if that causes mismatched tokens
|
||||
// Dev11 86819: We will allow empty matches if all subsequent segments are null
|
||||
if (blockAllUriAppends)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Append any pending literals to the URI (without the trailing slash) and prevent any future appends
|
||||
uri.Append(pendingParts.ToString(0, pendingParts.Length - 1));
|
||||
pendingParts.Length = 0;
|
||||
blockAllUriAppends = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pendingParts.Append("/");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PathContentSegment contentPathSegment = pathSegment as PathContentSegment;
|
||||
if (contentPathSegment != null)
|
||||
{
|
||||
// Segments are treated as all-or-none. We should never output a partial segment.
|
||||
// If we add any subsegment of this segment to the generated URI, we have to add
|
||||
// the complete match. For example, if the subsegment is "{p1}-{p2}.xml" and we
|
||||
// used a value for {p1}, we have to output the entire segment up to the next "/".
|
||||
// Otherwise we could end up with the partial segment "v1" instead of the entire
|
||||
// segment "v1-v2.xml".
|
||||
bool addedAnySubsegments = false;
|
||||
|
||||
foreach (PathSubsegment subsegment in contentPathSegment.Subsegments)
|
||||
{
|
||||
PathLiteralSubsegment literalSubsegment = subsegment as PathLiteralSubsegment;
|
||||
if (literalSubsegment != null)
|
||||
{
|
||||
// If it's a literal we hold on to it until we are sure we need to add it
|
||||
pendingPartsAreAllSafe = true;
|
||||
pendingParts.Append(literalSubsegment.Literal);
|
||||
}
|
||||
else
|
||||
{
|
||||
PathParameterSubsegment parameterSubsegment = subsegment as PathParameterSubsegment;
|
||||
if (parameterSubsegment != null)
|
||||
{
|
||||
if (pendingPartsAreAllSafe)
|
||||
{
|
||||
// Accept
|
||||
if (pendingParts.Length > 0)
|
||||
{
|
||||
if (blockAllUriAppends)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Append any pending literals to the URI
|
||||
uri.Append(pendingParts.ToString());
|
||||
pendingParts.Length = 0;
|
||||
|
||||
addedAnySubsegments = true;
|
||||
}
|
||||
}
|
||||
pendingPartsAreAllSafe = false;
|
||||
|
||||
// If it's a parameter, get its value
|
||||
object acceptedParameterValue;
|
||||
bool hasAcceptedParameterValue = acceptedValues.TryGetValue(parameterSubsegment.ParameterName, out acceptedParameterValue);
|
||||
if (hasAcceptedParameterValue)
|
||||
{
|
||||
unusedNewValues.Remove(parameterSubsegment.ParameterName);
|
||||
}
|
||||
|
||||
object defaultParameterValue;
|
||||
defaults.TryGetValue(parameterSubsegment.ParameterName, out defaultParameterValue);
|
||||
|
||||
if (RoutePartsEqual(acceptedParameterValue, defaultParameterValue))
|
||||
{
|
||||
// If the accepted value is the same as the default value, mark it as pending since
|
||||
// we won't necessarily add it to the URI we generate.
|
||||
pendingParts.Append(Convert.ToString(acceptedParameterValue, CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (blockAllUriAppends)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add the new part to the URI as well as any pending parts
|
||||
if (pendingParts.Length > 0)
|
||||
{
|
||||
// Append any pending literals to the URI
|
||||
uri.Append(pendingParts.ToString());
|
||||
pendingParts.Length = 0;
|
||||
}
|
||||
uri.Append(Convert.ToString(acceptedParameterValue, CultureInfo.InvariantCulture));
|
||||
|
||||
addedAnySubsegments = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Contract.Assert(false, "Invalid path subsegment type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addedAnySubsegments)
|
||||
{
|
||||
// See comment above about why we add the pending parts
|
||||
if (pendingParts.Length > 0)
|
||||
{
|
||||
if (blockAllUriAppends)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Append any pending literals to the URI
|
||||
uri.Append(pendingParts.ToString());
|
||||
pendingParts.Length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Contract.Assert(false, "Invalid path segment type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingPartsAreAllSafe)
|
||||
{
|
||||
// Accept
|
||||
if (pendingParts.Length > 0)
|
||||
{
|
||||
if (blockAllUriAppends)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Append any pending literals to the URI
|
||||
uri.Append(pendingParts.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// Process constraints keys
|
||||
if (constraints != null)
|
||||
{
|
||||
// If there are any constraints, mark all the keys as being used so that we don't
|
||||
// generate query string items for custom constraints that don't appear as parameters
|
||||
// in the URI format.
|
||||
foreach (var constraintsItem in constraints)
|
||||
{
|
||||
unusedNewValues.Remove(constraintsItem.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the URI before we append the query string, otherwise we would double encode the query string
|
||||
StringBuilder encodedUri = new StringBuilder();
|
||||
encodedUri.Append(UriEncode(uri.ToString()));
|
||||
uri = encodedUri;
|
||||
|
||||
// Add remaining new values as query string parameters to the URI
|
||||
if (unusedNewValues.Count > 0)
|
||||
{
|
||||
// Generate the query string
|
||||
bool firstParam = true;
|
||||
foreach (string unusedNewValue in unusedNewValues)
|
||||
{
|
||||
object value;
|
||||
if (acceptedValues.TryGetValue(unusedNewValue, out value))
|
||||
{
|
||||
uri.Append(firstParam ? '?' : '&');
|
||||
firstParam = false;
|
||||
uri.Append(Uri.EscapeDataString(unusedNewValue));
|
||||
uri.Append('=');
|
||||
uri.Append(Uri.EscapeDataString(Convert.ToString(value, CultureInfo.InvariantCulture)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new BoundRouteTemplate()
|
||||
{
|
||||
BoundTemplate = uri.ToString(),
|
||||
Values = acceptedValues
|
||||
};
|
||||
}
|
||||
|
||||
private static string EscapeReservedCharacters(Match m)
|
||||
{
|
||||
#if NET45
|
||||
return Uri.HexEscape(m.Value[0]);
|
||||
#else
|
||||
return m.Value;
|
||||
#endif
|
||||
}
|
||||
|
||||
private PathParameterSubsegment GetParameterSubsegment(IList<PathSegment> pathSegments, string parameterName)
|
||||
{
|
||||
for (int i = 0; i < this.ParameterSegments.Count; i++)
|
||||
{
|
||||
PathParameterSubsegment parameter = this.ParameterSegments[i];
|
||||
if (String.Equals(parameterName, parameter.ParameterName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsParameterRequired(PathParameterSubsegment parameterSubsegment, IDictionary<string, object> defaultValues, out object defaultValue)
|
||||
{
|
||||
if (parameterSubsegment.IsCatchAll)
|
||||
{
|
||||
defaultValue = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !defaultValues.TryGetValue(parameterSubsegment.ParameterName, out defaultValue);
|
||||
}
|
||||
|
||||
private static bool IsRoutePartNonEmpty(object routePart)
|
||||
{
|
||||
string routePartString = routePart as string;
|
||||
if (routePartString != null)
|
||||
{
|
||||
return routePartString.Length > 0;
|
||||
}
|
||||
return routePart != null;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Match(RoutingContext context, IDictionary<string, object> defaultValues)
|
||||
{
|
||||
List<string> requestPathSegments = RouteParser.SplitUriToPathSegmentStrings(context.RequestPath.Substring(1));
|
||||
|
||||
if (defaultValues == null)
|
||||
{
|
||||
defaultValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
Dictionary<string, object> matchedValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// This flag gets set once all the data in the URI has been parsed through, but
|
||||
// the route we're trying to match against still has more parts. At this point
|
||||
// we'll only continue matching separator characters and parameters that have
|
||||
// default values.
|
||||
bool ranOutOfStuffToParse = false;
|
||||
|
||||
// This value gets set once we start processing a catchall parameter (if there is one
|
||||
// at all). Once we set this value we consume all remaining parts of the URI into its
|
||||
// parameter value.
|
||||
bool usedCatchAllParameter = false;
|
||||
|
||||
for (int i = 0; i < PathSegments.Count; i++)
|
||||
{
|
||||
PathSegment pathSegment = PathSegments[i];
|
||||
|
||||
if (requestPathSegments.Count <= i)
|
||||
{
|
||||
ranOutOfStuffToParse = true;
|
||||
}
|
||||
|
||||
string requestPathSegment = ranOutOfStuffToParse ? null : requestPathSegments[i];
|
||||
|
||||
if (pathSegment is PathSeparatorSegment)
|
||||
{
|
||||
if (ranOutOfStuffToParse)
|
||||
{
|
||||
// If we're trying to match a separator in the route but there's no more content, that's OK
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!String.Equals(requestPathSegment, "/", StringComparison.Ordinal))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PathContentSegment contentPathSegment = pathSegment as PathContentSegment;
|
||||
if (contentPathSegment != null)
|
||||
{
|
||||
if (contentPathSegment.IsCatchAll)
|
||||
{
|
||||
Contract.Assert(i == (PathSegments.Count - 1), "If we're processing a catch-all, we should be on the last route segment.");
|
||||
MatchCatchAll(contentPathSegment, requestPathSegments.Skip(i), defaultValues, matchedValues);
|
||||
usedCatchAllParameter = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!MatchContentPathSegment(contentPathSegment, requestPathSegment, defaultValues, matchedValues))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Contract.Assert(false, "Invalid path segment type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!usedCatchAllParameter)
|
||||
{
|
||||
if (PathSegments.Count < requestPathSegments.Count)
|
||||
{
|
||||
// If we've already gone through all the parts defined in the route but the URI
|
||||
// still contains more content, check that the remaining content is all separators.
|
||||
for (int i = PathSegments.Count; i < requestPathSegments.Count; i++)
|
||||
{
|
||||
if (!RouteParser.IsSeparator(requestPathSegments[i]))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all remaining default values to the route data
|
||||
if (defaultValues != null)
|
||||
{
|
||||
foreach (var defaultValue in defaultValues)
|
||||
{
|
||||
if (!matchedValues.ContainsKey(defaultValue.Key))
|
||||
{
|
||||
matchedValues.Add(defaultValue.Key, defaultValue.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matchedValues;
|
||||
}
|
||||
|
||||
private static void MatchCatchAll(PathContentSegment contentPathSegment, IEnumerable<string> remainingRequestSegments, IDictionary<string, object> defaultValues, IDictionary<string, object> matchedValues)
|
||||
{
|
||||
string remainingRequest = String.Join(String.Empty, remainingRequestSegments.ToArray());
|
||||
|
||||
PathParameterSubsegment catchAllSegment = contentPathSegment.Subsegments[0] as PathParameterSubsegment;
|
||||
|
||||
object catchAllValue;
|
||||
|
||||
if (remainingRequest.Length > 0)
|
||||
{
|
||||
catchAllValue = remainingRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValues.TryGetValue(catchAllSegment.ParameterName, out catchAllValue);
|
||||
}
|
||||
|
||||
matchedValues.Add(catchAllSegment.ParameterName, catchAllValue);
|
||||
}
|
||||
|
||||
private static bool MatchContentPathSegment(PathContentSegment routeSegment, string requestPathSegment, IDictionary<string, object> defaultValues, IDictionary<string, object> matchedValues)
|
||||
{
|
||||
if (String.IsNullOrEmpty(requestPathSegment))
|
||||
{
|
||||
// If there's no data to parse, we must have exactly one parameter segment and no other segments - otherwise no match
|
||||
|
||||
if (routeSegment.Subsegments.Count > 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PathParameterSubsegment parameterSubsegment = routeSegment.Subsegments[0] as PathParameterSubsegment;
|
||||
if (parameterSubsegment == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must have a default value since there's no value in the request URI
|
||||
object parameterValue;
|
||||
if (defaultValues.TryGetValue(parameterSubsegment.ParameterName, out parameterValue))
|
||||
{
|
||||
// If there's a default value for this parameter, use that default value
|
||||
matchedValues.Add(parameterSubsegment.ParameterName, parameterValue);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's no default value, this segment doesn't match
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Optimize for the common case where there is only one subsegment in the segment - either a parameter or a literal
|
||||
if (routeSegment.Subsegments.Count == 1)
|
||||
{
|
||||
return MatchSingleContentPathSegment(routeSegment.Subsegments[0], requestPathSegment, matchedValues);
|
||||
}
|
||||
|
||||
// Find last literal segment and get its last index in the string
|
||||
|
||||
int lastIndex = requestPathSegment.Length;
|
||||
int indexOfLastSegmentUsed = routeSegment.Subsegments.Count - 1;
|
||||
|
||||
PathParameterSubsegment parameterNeedsValue = null; // Keeps track of a parameter segment that is pending a value
|
||||
PathLiteralSubsegment lastLiteral = null; // Keeps track of the left-most literal we've encountered
|
||||
|
||||
while (indexOfLastSegmentUsed >= 0)
|
||||
{
|
||||
int newLastIndex = lastIndex;
|
||||
|
||||
PathParameterSubsegment parameterSubsegment = routeSegment.Subsegments[indexOfLastSegmentUsed] as PathParameterSubsegment;
|
||||
if (parameterSubsegment != null)
|
||||
{
|
||||
// Hold on to the parameter so that we can fill it in when we locate the next literal
|
||||
parameterNeedsValue = parameterSubsegment;
|
||||
}
|
||||
else
|
||||
{
|
||||
PathLiteralSubsegment literalSubsegment = routeSegment.Subsegments[indexOfLastSegmentUsed] as PathLiteralSubsegment;
|
||||
if (literalSubsegment != null)
|
||||
{
|
||||
lastLiteral = literalSubsegment;
|
||||
|
||||
int startIndex = lastIndex - 1;
|
||||
// If we have a pending parameter subsegment, we must leave at least one character for that
|
||||
if (parameterNeedsValue != null)
|
||||
{
|
||||
startIndex--;
|
||||
}
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int indexOfLiteral = requestPathSegment.LastIndexOf(literalSubsegment.Literal, startIndex, StringComparison.OrdinalIgnoreCase);
|
||||
if (indexOfLiteral == -1)
|
||||
{
|
||||
// If we couldn't find this literal index, this segment cannot match
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the first subsegment is a literal, it must match at the right-most extent of the request URI.
|
||||
// Without this check if your route had "/Foo/" we'd match the request URI "/somethingFoo/".
|
||||
// This check is related to the check we do at the very end of this function.
|
||||
if (indexOfLastSegmentUsed == (routeSegment.Subsegments.Count - 1))
|
||||
{
|
||||
if ((indexOfLiteral + literalSubsegment.Literal.Length) != requestPathSegment.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
newLastIndex = indexOfLiteral;
|
||||
}
|
||||
else
|
||||
{
|
||||
Contract.Assert(false, "Invalid path segment type");
|
||||
}
|
||||
}
|
||||
|
||||
if ((parameterNeedsValue != null) && (((lastLiteral != null) && (parameterSubsegment == null)) || (indexOfLastSegmentUsed == 0)))
|
||||
{
|
||||
// If we have a pending parameter that needs a value, grab that value
|
||||
|
||||
int parameterStartIndex;
|
||||
int parameterTextLength;
|
||||
|
||||
if (lastLiteral == null)
|
||||
{
|
||||
if (indexOfLastSegmentUsed == 0)
|
||||
{
|
||||
parameterStartIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameterStartIndex = newLastIndex;
|
||||
Contract.Assert(false, "indexOfLastSegementUsed should always be 0 from the check above");
|
||||
}
|
||||
parameterTextLength = lastIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we're getting a value for a parameter that is somewhere in the middle of the segment
|
||||
if ((indexOfLastSegmentUsed == 0) && (parameterSubsegment != null))
|
||||
{
|
||||
parameterStartIndex = 0;
|
||||
parameterTextLength = lastIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
parameterStartIndex = newLastIndex + lastLiteral.Literal.Length;
|
||||
parameterTextLength = lastIndex - parameterStartIndex;
|
||||
}
|
||||
}
|
||||
|
||||
string parameterValueString = requestPathSegment.Substring(parameterStartIndex, parameterTextLength);
|
||||
|
||||
if (String.IsNullOrEmpty(parameterValueString))
|
||||
{
|
||||
// If we're here that means we have a segment that contains multiple sub-segments.
|
||||
// For these segments all parameters must have non-empty values. If the parameter
|
||||
// has an empty value it's not a match.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's a value in the segment for this parameter, use the subsegment value
|
||||
matchedValues.Add(parameterNeedsValue.ParameterName, parameterValueString);
|
||||
}
|
||||
|
||||
parameterNeedsValue = null;
|
||||
lastLiteral = null;
|
||||
}
|
||||
|
||||
lastIndex = newLastIndex;
|
||||
indexOfLastSegmentUsed--;
|
||||
}
|
||||
|
||||
// If the last subsegment is a parameter, it's OK that we didn't parse all the way to the left extent of
|
||||
// the string since the parameter will have consumed all the remaining text anyway. If the last subsegment
|
||||
// is a literal then we *must* have consumed the entire text in that literal. Otherwise we end up matching
|
||||
// the route "Foo" to the request URI "somethingFoo". Thus we have to check that we parsed the *entire*
|
||||
// request URI in order for it to be a match.
|
||||
// This check is related to the check we do earlier in this function for LiteralSubsegments.
|
||||
return (lastIndex == 0) || (routeSegment.Subsegments[0] is PathParameterSubsegment);
|
||||
}
|
||||
|
||||
private static bool MatchSingleContentPathSegment(PathSubsegment pathSubsegment, string requestPathSegment, IDictionary<string, object> matchedValues)
|
||||
{
|
||||
PathParameterSubsegment parameterSubsegment = pathSubsegment as PathParameterSubsegment;
|
||||
if (parameterSubsegment == null)
|
||||
{
|
||||
// Handle a single literal segment
|
||||
PathLiteralSubsegment literalSubsegment = pathSubsegment as PathLiteralSubsegment;
|
||||
Contract.Assert(literalSubsegment != null, "Invalid path segment type");
|
||||
return literalSubsegment.Literal.Equals(requestPathSegment, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle a single parameter segment
|
||||
matchedValues.Add(parameterSubsegment.ParameterName, requestPathSegment);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool RoutePartsEqual(object a, object b)
|
||||
{
|
||||
string sa = a as string;
|
||||
string sb = b as string;
|
||||
if (sa != null && sb != null)
|
||||
{
|
||||
// For strings do a case-insensitive comparison
|
||||
return String.Equals(sa, sb, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a != null && b != null)
|
||||
{
|
||||
// Explicitly call .Equals() in case it is overridden in the type
|
||||
return a.Equals(b);
|
||||
}
|
||||
else
|
||||
{
|
||||
// At least one of them is null. Return true if they both are
|
||||
return a == b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string UriEncode(string str)
|
||||
{
|
||||
string escape = Uri.EscapeUriString(str);
|
||||
return Regex.Replace(escape, "([#?])", new MatchEvaluator(EscapeReservedCharacters));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#if NET45
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Legacy
|
||||
{
|
||||
[SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable", Justification = "This class will never be serialized.")]
|
||||
public class HttpRouteValueDictionary : Dictionary<string, object>
|
||||
{
|
||||
public HttpRouteValueDictionary()
|
||||
: base(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
}
|
||||
|
||||
public HttpRouteValueDictionary(IDictionary<string, object> dictionary)
|
||||
: base(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
if (dictionary != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> current in dictionary)
|
||||
{
|
||||
Add(current.Key, current.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public HttpRouteValueDictionary(object values)
|
||||
: base(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
IDictionary<string, object> valuesAsDictionary = values as IDictionary<string, object>;
|
||||
if (valuesAsDictionary != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> current in valuesAsDictionary)
|
||||
{
|
||||
Add(current.Key, current.Value);
|
||||
}
|
||||
}
|
||||
else if (values != null)
|
||||
{
|
||||
foreach (PropertyHelper property in PropertyHelper.GetProperties(values))
|
||||
{
|
||||
// Extract the property values from the property helper
|
||||
// The advantage here is that the property helper caches fast accessors.
|
||||
Add(property.Name, property.GetValue(values));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Legacy
|
||||
{
|
||||
// Represents a segment of a URI such as a separator or content
|
||||
internal abstract class PathSegment
|
||||
{
|
||||
#if ROUTE_DEBUGGING
|
||||
public abstract string LiteralText
|
||||
{
|
||||
get;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Represents a segment of a URI that is not a separator. It contains subsegments such as literals and parameters.
|
||||
internal sealed class PathContentSegment : PathSegment
|
||||
{
|
||||
public PathContentSegment(List<PathSubsegment> subsegments)
|
||||
{
|
||||
Subsegments = subsegments;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Not changing original algorithm.")]
|
||||
public bool IsCatchAll
|
||||
{
|
||||
get
|
||||
{
|
||||
// TODO: Verify this is correct. Maybe add an assert.
|
||||
// Performance sensitive
|
||||
// Caching count is faster for IList<T>
|
||||
int subsegmentCount = Subsegments.Count;
|
||||
for (int i = 0; i < subsegmentCount; i++)
|
||||
{
|
||||
PathSubsegment seg = Subsegments[i];
|
||||
PathParameterSubsegment paramterSubSegment = seg as PathParameterSubsegment;
|
||||
if (paramterSubSegment != null && paramterSubSegment.IsCatchAll)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public List<PathSubsegment> Subsegments { get; private set; }
|
||||
|
||||
#if ROUTE_DEBUGGING
|
||||
public override string LiteralText
|
||||
{
|
||||
get
|
||||
{
|
||||
List<string> s = new List<string>();
|
||||
foreach (PathSubsegment subsegment in Subsegments)
|
||||
{
|
||||
s.Add(subsegment.LiteralText);
|
||||
}
|
||||
return String.Join(String.Empty, s.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
List<string> s = new List<string>();
|
||||
foreach (PathSubsegment subsegment in Subsegments)
|
||||
{
|
||||
s.Add(subsegment.ToString());
|
||||
}
|
||||
return "[ " + String.Join(", ", s.ToArray()) + " ]";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Represents a literal subsegment of a ContentPathSegment
|
||||
internal sealed class PathLiteralSubsegment : PathSubsegment
|
||||
{
|
||||
public PathLiteralSubsegment(string literal)
|
||||
{
|
||||
Literal = literal;
|
||||
}
|
||||
|
||||
public string Literal { get; private set; }
|
||||
|
||||
#if ROUTE_DEBUGGING
|
||||
public override string LiteralText
|
||||
{
|
||||
get
|
||||
{
|
||||
return Literal;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "\"" + Literal + "\"";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Represents a parameter subsegment of a ContentPathSegment
|
||||
internal sealed class PathParameterSubsegment : PathSubsegment
|
||||
{
|
||||
public PathParameterSubsegment(string parameterName)
|
||||
{
|
||||
if (parameterName.StartsWith("*", StringComparison.Ordinal))
|
||||
{
|
||||
ParameterName = parameterName.Substring(1);
|
||||
IsCatchAll = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParameterName = parameterName;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCatchAll { get; private set; }
|
||||
|
||||
public string ParameterName { get; private set; }
|
||||
|
||||
#if ROUTE_DEBUGGING
|
||||
public override string LiteralText
|
||||
{
|
||||
get
|
||||
{
|
||||
return "{" + (IsCatchAll ? "*" : String.Empty) + ParameterName + "}";
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" + (IsCatchAll ? "*" : String.Empty) + ParameterName + "}";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Represents a "/" separator in a URI
|
||||
internal sealed class PathSeparatorSegment : PathSegment
|
||||
{
|
||||
#if ROUTE_DEBUGGING
|
||||
public override string LiteralText
|
||||
{
|
||||
get
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "\"/\"";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Represents a subsegment of a ContentPathSegment such as a parameter or a literal.
|
||||
internal abstract class PathSubsegment
|
||||
{
|
||||
#if ROUTE_DEBUGGING
|
||||
public abstract string LiteralText
|
||||
{
|
||||
get;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#if NET45
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Legacy
|
||||
{
|
||||
internal class PropertyHelper
|
||||
{
|
||||
private static ConcurrentDictionary<Type, PropertyHelper[]> _reflectionCache = new ConcurrentDictionary<Type, PropertyHelper[]>();
|
||||
|
||||
private Func<object, object> _valueGetter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a fast property helper. This constructor does not cache the helper.
|
||||
/// </summary>
|
||||
[SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "This is intended the Name is auto set differently per type and the type is internal")]
|
||||
public PropertyHelper(PropertyInfo property)
|
||||
{
|
||||
Contract.Assert(property != null);
|
||||
|
||||
Name = property.Name;
|
||||
_valueGetter = MakeFastPropertyGetter(property);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a single fast property setter. The result is not cached.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
|
||||
/// <returns>a fast setter.</returns>
|
||||
/// <remarks>This method is more memory efficient than a dynamically compiled lambda, and about the same speed.</remarks>
|
||||
public static Action<TDeclaringType, object> MakeFastPropertySetter<TDeclaringType>(PropertyInfo propertyInfo)
|
||||
where TDeclaringType : class
|
||||
{
|
||||
Contract.Assert(propertyInfo != null);
|
||||
|
||||
MethodInfo setMethod = propertyInfo.GetSetMethod();
|
||||
|
||||
Contract.Assert(setMethod != null);
|
||||
Contract.Assert(!setMethod.IsStatic);
|
||||
Contract.Assert(setMethod.GetParameters().Length == 1);
|
||||
Contract.Assert(!propertyInfo.ReflectedType.IsValueType);
|
||||
|
||||
// Instance methods in the CLR can be turned into static methods where the first parameter
|
||||
// is open over "this". This parameter is always passed by reference, so we have a code
|
||||
// path for value types and a code path for reference types.
|
||||
Type typeInput = propertyInfo.ReflectedType;
|
||||
Type typeValue = setMethod.GetParameters()[0].ParameterType;
|
||||
|
||||
Delegate callPropertySetterDelegate;
|
||||
|
||||
// Create a delegate TValue -> "TDeclaringType.Property"
|
||||
var propertySetterAsAction = setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, typeValue));
|
||||
var callPropertySetterClosedGenericMethod = _callPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, typeValue);
|
||||
callPropertySetterDelegate = Delegate.CreateDelegate(typeof(Action<TDeclaringType, object>), propertySetterAsAction, callPropertySetterClosedGenericMethod);
|
||||
|
||||
return (Action<TDeclaringType, object>)callPropertySetterDelegate;
|
||||
}
|
||||
|
||||
public virtual string Name { get; protected set; }
|
||||
|
||||
public object GetValue(object instance)
|
||||
{
|
||||
Contract.Assert(_valueGetter != null, "Must call Initialize before using this object");
|
||||
|
||||
return _valueGetter(instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and caches fast property helpers that expose getters for every public get property on the underlying type.
|
||||
/// </summary>
|
||||
/// <param name="instance">the instance to extract property accessors for.</param>
|
||||
/// <returns>a cached array of all public property getters from the underlying type of this instance.</returns>
|
||||
public static PropertyHelper[] GetProperties(object instance)
|
||||
{
|
||||
return GetProperties(instance, CreateInstance, _reflectionCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a single fast property getter. The result is not cached.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">propertyInfo to extract the getter for.</param>
|
||||
/// <returns>a fast getter.</returns>
|
||||
/// <remarks>This method is more memory efficient than a dynamically compiled lambda, and about the same speed.</remarks>
|
||||
public static Func<object, object> MakeFastPropertyGetter(PropertyInfo propertyInfo)
|
||||
{
|
||||
Contract.Assert(propertyInfo != null);
|
||||
|
||||
MethodInfo getMethod = propertyInfo.GetGetMethod();
|
||||
Contract.Assert(getMethod != null);
|
||||
Contract.Assert(!getMethod.IsStatic);
|
||||
Contract.Assert(getMethod.GetParameters().Length == 0);
|
||||
|
||||
// Instance methods in the CLR can be turned into static methods where the first parameter
|
||||
// is open over "this". This parameter is always passed by reference, so we have a code
|
||||
// path for value types and a code path for reference types.
|
||||
Type typeInput = getMethod.ReflectedType;
|
||||
Type typeOutput = getMethod.ReturnType;
|
||||
|
||||
Delegate callPropertyGetterDelegate;
|
||||
if (typeInput.IsValueType)
|
||||
{
|
||||
// Create a delegate (ref TDeclaringType) -> TValue
|
||||
Delegate propertyGetterAsFunc = getMethod.CreateDelegate(typeof(ByRefFunc<,>).MakeGenericType(typeInput, typeOutput));
|
||||
MethodInfo callPropertyGetterClosedGenericMethod = _callPropertyGetterByReferenceOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
|
||||
callPropertyGetterDelegate = Delegate.CreateDelegate(typeof(Func<object, object>), propertyGetterAsFunc, callPropertyGetterClosedGenericMethod);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a delegate TDeclaringType -> TValue
|
||||
Delegate propertyGetterAsFunc = getMethod.CreateDelegate(typeof(Func<,>).MakeGenericType(typeInput, typeOutput));
|
||||
MethodInfo callPropertyGetterClosedGenericMethod = _callPropertyGetterOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);
|
||||
callPropertyGetterDelegate = Delegate.CreateDelegate(typeof(Func<object, object>), propertyGetterAsFunc, callPropertyGetterClosedGenericMethod);
|
||||
}
|
||||
|
||||
return (Func<object, object>)callPropertyGetterDelegate;
|
||||
}
|
||||
|
||||
private static PropertyHelper CreateInstance(PropertyInfo property)
|
||||
{
|
||||
return new PropertyHelper(property);
|
||||
}
|
||||
|
||||
// Implementation of the fast getter.
|
||||
private delegate TValue ByRefFunc<TDeclaringType, TValue>(ref TDeclaringType arg);
|
||||
|
||||
private static readonly MethodInfo _callPropertyGetterOpenGenericMethod = typeof(PropertyHelper).GetMethod("CallPropertyGetter", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
private static readonly MethodInfo _callPropertyGetterByReferenceOpenGenericMethod = typeof(PropertyHelper).GetMethod("CallPropertyGetterByReference", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
private static object CallPropertyGetter<TDeclaringType, TValue>(Func<TDeclaringType, TValue> getter, object @this)
|
||||
{
|
||||
return getter((TDeclaringType)@this);
|
||||
}
|
||||
|
||||
private static object CallPropertyGetterByReference<TDeclaringType, TValue>(ByRefFunc<TDeclaringType, TValue> getter, object @this)
|
||||
{
|
||||
TDeclaringType unboxed = (TDeclaringType)@this;
|
||||
return getter(ref unboxed);
|
||||
}
|
||||
|
||||
// Implementation of the fast setter.
|
||||
private static readonly MethodInfo _callPropertySetterOpenGenericMethod = typeof(PropertyHelper).GetMethod("CallPropertySetter", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
|
||||
private static void CallPropertySetter<TDeclaringType, TValue>(Action<TDeclaringType, TValue> setter, object @this, object value)
|
||||
{
|
||||
setter((TDeclaringType)@this, (TValue)value);
|
||||
}
|
||||
|
||||
protected static PropertyHelper[] GetProperties(object instance,
|
||||
Func<PropertyInfo, PropertyHelper> createPropertyHelper,
|
||||
ConcurrentDictionary<Type, PropertyHelper[]> cache)
|
||||
{
|
||||
// Using an array rather than IEnumerable, as this will be called on the hot path numerous times.
|
||||
PropertyHelper[] helpers;
|
||||
|
||||
Type type = instance.GetType();
|
||||
|
||||
if (!cache.TryGetValue(type, out helpers))
|
||||
{
|
||||
// We avoid loading indexed properties using the where statement.
|
||||
// Indexed properties are not useful (or valid) for grabbing properties off an anonymous object.
|
||||
IEnumerable<PropertyInfo> properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(prop => prop.GetIndexParameters().Length == 0 &&
|
||||
prop.GetMethod != null);
|
||||
|
||||
var newHelpers = new List<PropertyHelper>();
|
||||
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
PropertyHelper propertyHelper = createPropertyHelper(property);
|
||||
|
||||
newHelpers.Add(propertyHelper);
|
||||
}
|
||||
|
||||
helpers = newHelpers.ToArray();
|
||||
cache.TryAdd(type, helpers);
|
||||
}
|
||||
|
||||
return helpers;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,377 +0,0 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
#define ASPNETWEBAPI
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
|
||||
#if ASPNETWEBAPI
|
||||
using TParsedRoute = Microsoft.AspNet.Routing.Legacy.HttpParsedRoute;
|
||||
#else
|
||||
using ErrorResources = System.Web.Mvc.Properties.MvcResources;
|
||||
using TParsedRoute = System.Web.Mvc.Routing.ParsedRoute;
|
||||
#endif
|
||||
|
||||
#if ASPNETWEBAPI
|
||||
namespace Microsoft.AspNet.Routing.Legacy
|
||||
#else
|
||||
namespace System.Web.Mvc.Routing
|
||||
#endif
|
||||
{
|
||||
// in the MVC case, route parsing is done for AttributeRouting's sake, so that
|
||||
// it could order the discovered routes before pushing them into the routeCollection,
|
||||
// where, unfortunately, they would be parsed again.
|
||||
internal static class RouteParser
|
||||
{
|
||||
private static string GetLiteral(string segmentLiteral)
|
||||
{
|
||||
// Scan for errant single { and } and convert double {{ to { and double }} to }
|
||||
|
||||
// First we eliminate all escaped braces and then check if any other braces are remaining
|
||||
string newLiteral = segmentLiteral.Replace("{{", String.Empty).Replace("}}", String.Empty);
|
||||
if (newLiteral.Contains("{") || newLiteral.Contains("}"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// If it's a valid format, we unescape the braces
|
||||
return segmentLiteral.Replace("{{", "{").Replace("}}", "}");
|
||||
}
|
||||
|
||||
private static int IndexOfFirstOpenParameter(string segment, int startIndex)
|
||||
{
|
||||
// Find the first unescaped open brace
|
||||
while (true)
|
||||
{
|
||||
startIndex = segment.IndexOf('{', startIndex);
|
||||
if (startIndex == -1)
|
||||
{
|
||||
// If there are no more open braces, stop
|
||||
return -1;
|
||||
}
|
||||
if ((startIndex + 1 == segment.Length) ||
|
||||
((startIndex + 1 < segment.Length) && (segment[startIndex + 1] != '{')))
|
||||
{
|
||||
// If we found an open brace that is followed by a non-open brace, it's
|
||||
// a parameter delimiter.
|
||||
// It's also a delimiter if the open brace is the last character - though
|
||||
// it ends up being being called out as invalid later on.
|
||||
return startIndex;
|
||||
}
|
||||
// Increment by two since we want to skip both the open brace that
|
||||
// we're on as well as the subsequent character since we know for
|
||||
// sure that it is part of an escape sequence.
|
||||
startIndex += 2;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsSeparator(string s)
|
||||
{
|
||||
return String.Equals(s, "/", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static bool IsValidParameterName(string parameterName)
|
||||
{
|
||||
if (parameterName.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < parameterName.Length; i++)
|
||||
{
|
||||
char c = parameterName[i];
|
||||
if (c == '/' || c == '{' || c == '}')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool IsInvalidRouteTemplate(string routeTemplate)
|
||||
{
|
||||
return routeTemplate.StartsWith("~", StringComparison.Ordinal) ||
|
||||
routeTemplate.StartsWith("/", StringComparison.Ordinal) ||
|
||||
(routeTemplate.IndexOf('?') != -1);
|
||||
}
|
||||
|
||||
public static TParsedRoute Parse(string routeTemplate)
|
||||
{
|
||||
if (routeTemplate == null)
|
||||
{
|
||||
routeTemplate = String.Empty;
|
||||
}
|
||||
|
||||
if (IsInvalidRouteTemplate(routeTemplate))
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
IList<string> uriParts = SplitUriToPathSegmentStrings(routeTemplate);
|
||||
Exception ex = ValidateUriParts(uriParts);
|
||||
if (ex != null)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
List<PathSegment> pathSegments = SplitUriToPathSegments(uriParts);
|
||||
|
||||
Contract.Assert(uriParts.Count == pathSegments.Count, "The number of string segments should be the same as the number of path segments");
|
||||
|
||||
return new TParsedRoute(pathSegments);
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly",
|
||||
Justification = "The exceptions are just constructed here, but they are thrown from a method that does have those parameter names.")]
|
||||
private static List<PathSubsegment> ParseUriSegment(string segment, out Exception exception)
|
||||
{
|
||||
int startIndex = 0;
|
||||
|
||||
List<PathSubsegment> pathSubsegments = new List<PathSubsegment>();
|
||||
|
||||
while (startIndex < segment.Length)
|
||||
{
|
||||
int nextParameterStart = IndexOfFirstOpenParameter(segment, startIndex);
|
||||
if (nextParameterStart == -1)
|
||||
{
|
||||
// If there are no more parameters in the segment, capture the remainder as a literal and stop
|
||||
string lastLiteralPart = GetLiteral(segment.Substring(startIndex));
|
||||
if (lastLiteralPart == null)
|
||||
{
|
||||
exception = new ArgumentException();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (lastLiteralPart.Length > 0)
|
||||
{
|
||||
pathSubsegments.Add(new PathLiteralSubsegment(lastLiteralPart));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int nextParameterEnd = segment.IndexOf('}', nextParameterStart + 1);
|
||||
if (nextParameterEnd == -1)
|
||||
{
|
||||
exception = new ArgumentException();
|
||||
return null;
|
||||
}
|
||||
|
||||
string literalPart = GetLiteral(segment.Substring(startIndex, nextParameterStart - startIndex));
|
||||
if (literalPart == null)
|
||||
{
|
||||
exception = new ArgumentException();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (literalPart.Length > 0)
|
||||
{
|
||||
pathSubsegments.Add(new PathLiteralSubsegment(literalPart));
|
||||
}
|
||||
|
||||
string parameterName = segment.Substring(nextParameterStart + 1, nextParameterEnd - nextParameterStart - 1);
|
||||
pathSubsegments.Add(new PathParameterSubsegment(parameterName));
|
||||
|
||||
startIndex = nextParameterEnd + 1;
|
||||
}
|
||||
|
||||
exception = null;
|
||||
return pathSubsegments;
|
||||
}
|
||||
|
||||
private static List<PathSegment> SplitUriToPathSegments(IList<string> uriParts)
|
||||
{
|
||||
List<PathSegment> pathSegments = new List<PathSegment>();
|
||||
|
||||
foreach (string pathSegment in uriParts)
|
||||
{
|
||||
bool isCurrentPartSeparator = IsSeparator(pathSegment);
|
||||
if (isCurrentPartSeparator)
|
||||
{
|
||||
pathSegments.Add(new PathSeparatorSegment());
|
||||
}
|
||||
else
|
||||
{
|
||||
Exception exception;
|
||||
List<PathSubsegment> subsegments = ParseUriSegment(pathSegment, out exception);
|
||||
Contract.Assert(exception == null, "This only gets called after the path has been validated, so there should never be an exception here");
|
||||
pathSegments.Add(new PathContentSegment(subsegments));
|
||||
}
|
||||
}
|
||||
return pathSegments;
|
||||
}
|
||||
|
||||
internal static List<string> SplitUriToPathSegmentStrings(string uri)
|
||||
{
|
||||
List<string> parts = new List<string>();
|
||||
|
||||
if (String.IsNullOrEmpty(uri))
|
||||
{
|
||||
return parts;
|
||||
}
|
||||
|
||||
int currentIndex = 0;
|
||||
|
||||
// Split the incoming URI into individual parts
|
||||
while (currentIndex < uri.Length)
|
||||
{
|
||||
int indexOfNextSeparator = uri.IndexOf('/', currentIndex);
|
||||
if (indexOfNextSeparator == -1)
|
||||
{
|
||||
// If there are no more separators, the rest of the string is the last part
|
||||
string finalPart = uri.Substring(currentIndex);
|
||||
if (finalPart.Length > 0)
|
||||
{
|
||||
parts.Add(finalPart);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
string nextPart = uri.Substring(currentIndex, indexOfNextSeparator - currentIndex);
|
||||
if (nextPart.Length > 0)
|
||||
{
|
||||
parts.Add(nextPart);
|
||||
}
|
||||
|
||||
Contract.Assert(uri[indexOfNextSeparator] == '/', "The separator char itself should always be a '/'.");
|
||||
parts.Add("/");
|
||||
currentIndex = indexOfNextSeparator + 1;
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Not changing original algorithm")]
|
||||
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly",
|
||||
Justification = "The exceptions are just constructed here, but they are thrown from a method that does have those parameter names.")]
|
||||
private static Exception ValidateUriParts(IList<string> pathSegments)
|
||||
{
|
||||
Contract.Assert(pathSegments != null, "The value should always come from SplitUri(), and that function should never return null.");
|
||||
|
||||
HashSet<string> usedParameterNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
bool? isPreviousPartSeparator = null;
|
||||
|
||||
bool foundCatchAllParameter = false;
|
||||
|
||||
foreach (string pathSegment in pathSegments)
|
||||
{
|
||||
if (foundCatchAllParameter)
|
||||
{
|
||||
// If we ever start an iteration of the loop and we've already found a
|
||||
// catchall parameter then we have an invalid URI format.
|
||||
return new ArgumentException();
|
||||
}
|
||||
|
||||
bool isCurrentPartSeparator;
|
||||
if (isPreviousPartSeparator == null)
|
||||
{
|
||||
// Prime the loop with the first value
|
||||
isPreviousPartSeparator = IsSeparator(pathSegment);
|
||||
isCurrentPartSeparator = isPreviousPartSeparator.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCurrentPartSeparator = IsSeparator(pathSegment);
|
||||
|
||||
// If both the previous part and the current part are separators, it's invalid
|
||||
if (isCurrentPartSeparator && isPreviousPartSeparator.Value)
|
||||
{
|
||||
return new ArgumentException();
|
||||
}
|
||||
|
||||
Contract.Assert(isCurrentPartSeparator != isPreviousPartSeparator.Value, "This assert should only happen if both the current and previous parts are non-separators. This should never happen because consecutive non-separators are always parsed as a single part.");
|
||||
isPreviousPartSeparator = isCurrentPartSeparator;
|
||||
}
|
||||
|
||||
// If it's not a separator, parse the segment for parameters and validate it
|
||||
if (!isCurrentPartSeparator)
|
||||
{
|
||||
Exception exception;
|
||||
IList<PathSubsegment> subsegments = ParseUriSegment(pathSegment, out exception);
|
||||
if (exception != null)
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
|
||||
exception = ValidateUriSegment(subsegments, usedParameterNames);
|
||||
if (exception != null)
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
|
||||
foundCatchAllParameter = subsegments.Any<PathSubsegment>(seg => (seg is PathParameterSubsegment) && ((PathParameterSubsegment)seg).IsCatchAll);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly",
|
||||
Justification = "The exceptions are just constructed here, but they are thrown from a method that does have those parameter names.")]
|
||||
private static Exception ValidateUriSegment(IList<PathSubsegment> pathSubsegments, HashSet<string> usedParameterNames)
|
||||
{
|
||||
bool segmentContainsCatchAll = false;
|
||||
|
||||
Type previousSegmentType = null;
|
||||
|
||||
foreach (PathSubsegment subsegment in pathSubsegments)
|
||||
{
|
||||
if (previousSegmentType != null)
|
||||
{
|
||||
if (previousSegmentType == subsegment.GetType())
|
||||
{
|
||||
return new ArgumentException();
|
||||
}
|
||||
}
|
||||
previousSegmentType = subsegment.GetType();
|
||||
|
||||
PathLiteralSubsegment literalSubsegment = subsegment as PathLiteralSubsegment;
|
||||
if (literalSubsegment != null)
|
||||
{
|
||||
// Nothing to validate for literals - everything is valid
|
||||
}
|
||||
else
|
||||
{
|
||||
PathParameterSubsegment parameterSubsegment = subsegment as PathParameterSubsegment;
|
||||
if (parameterSubsegment != null)
|
||||
{
|
||||
string parameterName = parameterSubsegment.ParameterName;
|
||||
|
||||
if (parameterSubsegment.IsCatchAll)
|
||||
{
|
||||
segmentContainsCatchAll = true;
|
||||
}
|
||||
|
||||
// Check for valid characters in the parameter name
|
||||
if (!IsValidParameterName(parameterName))
|
||||
{
|
||||
return new ArgumentException();
|
||||
}
|
||||
|
||||
if (usedParameterNames.Contains(parameterName))
|
||||
{
|
||||
return new ArgumentException();
|
||||
}
|
||||
else
|
||||
{
|
||||
usedParameterNames.Add(parameterName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Contract.Assert(false, "Invalid path subsegment type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (segmentContainsCatchAll && (pathSubsegments.Count != 1))
|
||||
{
|
||||
return new ArgumentException();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
#if NET45
|
||||
|
||||
using Owin;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Owin
|
||||
{
|
||||
public static class AppBuilderExtensions
|
||||
{
|
||||
public static IRouteBuilder UseRouter(this IAppBuilder builder)
|
||||
{
|
||||
var routes = new RouteTable();
|
||||
var engine = new RouteEngine(routes);
|
||||
|
||||
var next = builder.Use(typeof(RouterMiddleware), engine, routes);
|
||||
|
||||
return new RouteBuilder(next, engine, routes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Owin
|
||||
{
|
||||
internal class AppFuncMiddleware
|
||||
{
|
||||
public AppFuncMiddleware(Func<IDictionary<string, object>, Task> next, Func<IDictionary<string, object>, Task> appFunc)
|
||||
{
|
||||
this.Next = next;
|
||||
this.AppFunc = appFunc;
|
||||
}
|
||||
|
||||
private Func<IDictionary<string, object>, Task> AppFunc
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private Func<IDictionary<string, object>, Task> Next
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Task Invoke(IDictionary<string, object> context)
|
||||
{
|
||||
return this.AppFunc(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
#if NET45
|
||||
using Owin;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Owin
|
||||
{
|
||||
internal class RouteBuilder : IRouteBuilder
|
||||
{
|
||||
#if NET45
|
||||
public RouteBuilder(IAppBuilder builder, IRouteEngine engine, RouteTable routes)
|
||||
{
|
||||
this.AppBuilder = builder;
|
||||
this.Engine = engine;
|
||||
this.Routes = routes;
|
||||
}
|
||||
#else
|
||||
public RouteBuilder(IRouteEngine engine, RouteTable routes)
|
||||
{
|
||||
this.Engine = engine;
|
||||
this.Routes = routes;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET45
|
||||
public IAppBuilder AppBuilder
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
#endif
|
||||
|
||||
public IRouteEngine Engine
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private RouteTable Routes
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public IRouteEndpoint ForApp(Func<Func<IDictionary<string, object>, Task>> handlerFactory)
|
||||
{
|
||||
return new RouteEndpoint(handlerFactory(), this.Routes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Owin
|
||||
{
|
||||
internal class RouteEndpoint : IRouteEndpoint
|
||||
{
|
||||
public RouteEndpoint(Func<IDictionary<string, object>, Task> appFunc, RouteTable routes)
|
||||
{
|
||||
this.AppFunc = appFunc;
|
||||
this.Routes = routes;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, object>, Task> AppFunc
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private RouteTable Routes
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public IRouteEndpoint AddRoute(string name, IRoute route)
|
||||
{
|
||||
this.Routes.Add(name, route);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Owin
|
||||
{
|
||||
public class RouterMiddleware
|
||||
{
|
||||
public RouterMiddleware(Func<IDictionary<string, object>, Task> next, IRouteEngine engine, RouteTable routes)
|
||||
{
|
||||
this.Next = next;
|
||||
this.Engine = engine;
|
||||
this.Routes = routes;
|
||||
}
|
||||
|
||||
private IRouteEngine Engine
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private Func<IDictionary<string, object>, Task> Next
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private RouteTable Routes
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public Task Invoke(IDictionary<string, object> context)
|
||||
{
|
||||
var match = this.Engine.GetMatch(context);
|
||||
if (match == null)
|
||||
{
|
||||
return Next.Invoke(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
return match.Destination.Invoke(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class PrefixRoute : IRoute
|
||||
{
|
||||
public PrefixRoute(IRouteEndpoint endpoint, string prefix)
|
||||
{
|
||||
this.Endpoint = endpoint;
|
||||
|
||||
if (prefix != null)
|
||||
{
|
||||
if (prefix.Length == 0 || prefix[0] != '/')
|
||||
{
|
||||
prefix = '/' + prefix;
|
||||
}
|
||||
|
||||
if (prefix.Length > 1 && prefix[prefix.Length - 1] == '/')
|
||||
{
|
||||
prefix = prefix.Substring(0, prefix.Length - 1);
|
||||
}
|
||||
|
||||
this.Prefix = prefix;
|
||||
}
|
||||
}
|
||||
|
||||
private IRouteEndpoint Endpoint
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private string Prefix
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public virtual BoundRoute Bind(RouteBindingContext context)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual RouteMatch GetMatch(RoutingContext context)
|
||||
{
|
||||
if (this.Prefix == null)
|
||||
{
|
||||
return new RouteMatch(this.Endpoint.AppFunc);
|
||||
}
|
||||
else if (context.RequestPath.StartsWith(this.Prefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (context.RequestPath.Length > this.Prefix.Length)
|
||||
{
|
||||
char next = context.RequestPath[this.Prefix.Length];
|
||||
if (next != '/' && next != '#' && next != '?')
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new RouteMatch(this.Endpoint.AppFunc);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Microsoft.AspNet.Routing")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Microsoft.AspNet.Routing")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("625c3577-6c55-4ed0-80cc-3b3481955bd0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RouteBindingContext
|
||||
{
|
||||
public RouteBindingContext(IDictionary<string, object> context, IDictionary<string, object> values)
|
||||
{
|
||||
this.Context = context;
|
||||
this.Values = values;
|
||||
|
||||
this.AmbientValues = context.GetRouteMatchValues();
|
||||
}
|
||||
|
||||
public IDictionary<string, object> AmbientValues
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Context
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Values
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
using System;
|
||||
#if NET45
|
||||
using Owin;
|
||||
#endif
|
||||
|
||||
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public static class RouteBuilderExtensions
|
||||
{
|
||||
#if NET45
|
||||
public static IRouteEndpoint ForApp(this IRouteBuilder routeBuilder, Func<IAppBuilder, IRouteEngine, IAppBuilder> handlerBuilder)
|
||||
{
|
||||
var builder = handlerBuilder.Invoke(routeBuilder.AppBuilder.New(), routeBuilder.Engine);
|
||||
var appFunc = (AppFunc)builder.Build(typeof(AppFunc));
|
||||
return routeBuilder.ForApp(() => appFunc);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint ForApp(this IRouteBuilder routeBuilder, Action<IAppBuilder, IRouteEngine> handlerBuilder)
|
||||
{
|
||||
return routeBuilder.ForApp((builder, engine) => { handlerBuilder(builder, engine); return builder; });
|
||||
}
|
||||
|
||||
public static IRouteEndpoint ForApp(this IRouteBuilder routeBuilder, Action<IAppBuilder> handlerBuilder)
|
||||
{
|
||||
return routeBuilder.ForApp((builder, engine) => { handlerBuilder(builder); return builder; });
|
||||
}
|
||||
|
||||
public static IRouteEndpoint ForApp(this IRouteBuilder routeBuilder, Func<IAppBuilder, IAppBuilder> handlerBuilder)
|
||||
{
|
||||
return routeBuilder.ForApp((builder, engine) => handlerBuilder(builder));
|
||||
}
|
||||
#endif
|
||||
public static IRouteEndpoint ForApp(this IRouteBuilder routeBuilder, Func<AppFunc, AppFunc> handlerBuilder)
|
||||
{
|
||||
return routeBuilder.ForApp(() => handlerBuilder(null));
|
||||
}
|
||||
|
||||
public static IRouteEndpoint ForApp(this IRouteBuilder routeBuilder, AppFunc handler)
|
||||
{
|
||||
return routeBuilder.ForApp((Func<AppFunc, AppFunc>)((next) => handler));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RouteEngine : IRouteEngine
|
||||
{
|
||||
public RouteEngine(RouteTable routes)
|
||||
{
|
||||
this.Routes = routes;
|
||||
}
|
||||
|
||||
public RouteTable Routes
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public RouteMatch GetMatch(IDictionary<string, object> context)
|
||||
{
|
||||
var routingContext = new RoutingContext(context);
|
||||
|
||||
for (int i = 0; i < this.Routes.Routes.Count; i++)
|
||||
{
|
||||
var route = this.Routes.Routes[i];
|
||||
|
||||
var match = route.GetMatch(routingContext);
|
||||
if (match == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
context.SetRouteMatchValues(match.Values);
|
||||
context.SetRouteEngine(this);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public BoundRoute GetUrl(string name, IDictionary<string, object> context, IDictionary<string, object> values)
|
||||
{
|
||||
var bindingContext = new RouteBindingContext(context, values);
|
||||
|
||||
IRoute route;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
if (Routes.NamedRoutes.TryGetValue(name, out route))
|
||||
{
|
||||
return route.Bind(bindingContext);
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < this.Routes.Routes.Count; j++)
|
||||
{
|
||||
route = this.Routes.Routes[j];
|
||||
|
||||
var result = route.Bind(bindingContext);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public static class RouteEngineExtensions
|
||||
{
|
||||
public static BoundRoute GetUrl(this IRouteEngine engine, IDictionary<string, object> context, IDictionary<string, object> values)
|
||||
{
|
||||
return engine.GetUrl(null, context, values);
|
||||
}
|
||||
|
||||
public static BoundRoute GetUrl(this IRouteEngine engine, string name, IDictionary<string, object> context, IDictionary<string, object> values)
|
||||
{
|
||||
return engine.GetUrl(name, context, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RouteMatch
|
||||
{
|
||||
public RouteMatch(Func<IDictionary<string, object>, Task> destination)
|
||||
: this(destination, null)
|
||||
{
|
||||
}
|
||||
|
||||
public RouteMatch(Func<IDictionary<string, object>, Task> destination, IDictionary<string, object> values)
|
||||
{
|
||||
this.Destination = destination;
|
||||
this.Values = values;
|
||||
}
|
||||
|
||||
public Func<IDictionary<string, object>, Task> Destination
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Values
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RouteTable
|
||||
{
|
||||
public RouteTable()
|
||||
{
|
||||
this.Routes = new List<IRoute>();
|
||||
|
||||
this.NamedRoutes = new Dictionary<string, IRoute>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public List<IRoute> Routes
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public IDictionary<string, IRoute> NamedRoutes
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public void Add(IRoute route)
|
||||
{
|
||||
this.Add(null, route);
|
||||
}
|
||||
|
||||
public void Add(string name, IRoute route)
|
||||
{
|
||||
this.Routes.Add(route);
|
||||
|
||||
if (!String.IsNullOrEmpty(name))
|
||||
{
|
||||
this.NamedRoutes.Add(name, route);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing
|
||||
{
|
||||
public class RoutingContext
|
||||
{
|
||||
public RoutingContext(IDictionary<string, object> context)
|
||||
{
|
||||
this.Context = context;
|
||||
|
||||
this.RequestMethod = (string)context["owin.RequestMethod"];
|
||||
this.RequestPath = (string)context["owin.RequestPath"];
|
||||
}
|
||||
|
||||
public IDictionary<string, object> Context
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string RequestMethod
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string RequestPath
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Routing.Legacy;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Template
|
||||
{
|
||||
public class TemplateRoute : IRoute
|
||||
{
|
||||
public TemplateRoute(IRouteEndpoint destination, string template)
|
||||
: this(destination, template, null, null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public TemplateRoute(IRouteEndpoint destination, string template, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> data)
|
||||
{
|
||||
this.Destination = destination;
|
||||
this.Template = template;
|
||||
this.Defaults = defaults;
|
||||
this.Constraints = constraints;
|
||||
this.Data = data;
|
||||
|
||||
this.ParsedRoute = RouteParser.Parse(template);
|
||||
|
||||
this.Initialize();
|
||||
}
|
||||
|
||||
private IDictionary<string, object> Constraints
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private IDictionary<string, object> Data
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private IRouteEndpoint Destination
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> FilterValues
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Defaults;
|
||||
}
|
||||
}
|
||||
|
||||
private IDictionary<string, object> Defaults
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private List<KeyValuePair<string, IConstraint>> ConstraintsInternal
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private HttpParsedRoute ParsedRoute
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private string Template
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public RouteMatch GetMatch(RoutingContext context)
|
||||
{
|
||||
var match = this.ParsedRoute.Match(context, this.Defaults);
|
||||
if (match == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.ConstraintsInternal.Count; i++)
|
||||
{
|
||||
var kvp = this.ConstraintsInternal[i];
|
||||
|
||||
object value = null;
|
||||
if (!String.IsNullOrEmpty(kvp.Key))
|
||||
{
|
||||
match.TryGetValue(kvp.Key, out value);
|
||||
}
|
||||
|
||||
if (!kvp.Value.MatchInbound(context, match, value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new RouteMatch(this.Destination.AppFunc, match);
|
||||
}
|
||||
|
||||
public bool OnSelected(IDictionary<string, object> context, RouteMatch match)
|
||||
{
|
||||
if (this.Data != null)
|
||||
{
|
||||
foreach (var kvp in this.Data)
|
||||
{
|
||||
context[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public BoundRoute Bind(RouteBindingContext context)
|
||||
{
|
||||
var template = this.ParsedRoute.Bind(context, this.Defaults);
|
||||
if (template == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.ConstraintsInternal.Count; i++)
|
||||
{
|
||||
var kvp = this.ConstraintsInternal[i];
|
||||
|
||||
object value = null;
|
||||
if (!String.IsNullOrEmpty(kvp.Key))
|
||||
{
|
||||
template.Values.TryGetValue(kvp.Key, out value);
|
||||
}
|
||||
|
||||
if (!kvp.Value.MatchOutbound(context, template.Values, value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new BoundRoute(template.BoundTemplate, template.Values);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
this.ConstraintsInternal = new List<KeyValuePair<string, IConstraint>>();
|
||||
|
||||
if (this.Constraints == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var kvp in this.Constraints)
|
||||
{
|
||||
string constraintString;
|
||||
IConstraint constraint;
|
||||
|
||||
if ((constraintString = kvp.Value as string) != null)
|
||||
{
|
||||
// TODO regex constraints
|
||||
}
|
||||
else if ((constraint = kvp.Value as IConstraint) != null)
|
||||
{
|
||||
this.ConstraintsInternal.Add(new KeyValuePair<string, IConstraint>(kvp.Key, constraint));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Template
|
||||
{
|
||||
public static class HttpMethodRouteExtensions
|
||||
{
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string template)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(null, template, null, null, null);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string template, IDictionary<string, object> defaults)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(null, template, defaults, null, null);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string template, IDictionary<string, object> defaults, IDictionary<string, object> constraints)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(null, template, defaults, constraints, null);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string template, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> data)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(null, template, defaults, constraints, data);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string name, string template)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(name, template, null, null, null);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string name, string template, IDictionary<string, object> defaults)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(name, template, defaults, null, null);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string name, string template, IDictionary<string, object> defaults, IDictionary<string, object> constraints)
|
||||
{
|
||||
return endpoint.AddTemplateRoute(name, template, defaults, constraints, null);
|
||||
}
|
||||
|
||||
public static IRouteEndpoint AddTemplateRoute(this IRouteEndpoint endpoint, string name, string template, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> data)
|
||||
{
|
||||
return endpoint.AddRoute(name, new TemplateRoute(endpoint, template, defaults, constraints, data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
public interface ITreeRouteBuilder
|
||||
{
|
||||
void Build();
|
||||
|
||||
ITreeRouteBuilder Endpoint(IRouteEndpoint endpoint);
|
||||
|
||||
ITreeRouteBuilder Segment(Func<ITreeSegment> segmentBuilder);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
public interface ITreeSegment
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
internal class ParameterSegment : ITreeSegment
|
||||
{
|
||||
public ParameterSegment(string name)
|
||||
{
|
||||
this.Name = name;
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
internal class PathSegment : ITreeSegment
|
||||
{
|
||||
public PathSegment(string path)
|
||||
{
|
||||
this.Path = path;
|
||||
}
|
||||
|
||||
private string Path
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
public class TreeRoute : IRoute
|
||||
{
|
||||
public BoundRoute Bind(RouteBindingContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public RouteMatch GetMatch(RoutingContext context)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
internal class TreeRouteBuilder : ITreeRouteBuilder
|
||||
{
|
||||
public TreeRouteBuilder(IRouteBuilder routeBuilder)
|
||||
{
|
||||
this.RouteBuilder = routeBuilder;
|
||||
}
|
||||
|
||||
public TreeRouteBuilder(Func<ITreeSegment> current, TreeRouteBuilder parent)
|
||||
{
|
||||
this.Current = current;
|
||||
this.Parent = parent;
|
||||
|
||||
this.RouteBuilder = parent.RouteBuilder;
|
||||
this.RouteEndpoint = parent.RouteEndpoint;
|
||||
}
|
||||
|
||||
private Func<ITreeSegment> Current
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private TreeRouteBuilder Parent
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private IRouteBuilder RouteBuilder
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private IRouteEndpoint RouteEndpoint
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public void Build()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ITreeRouteBuilder Endpoint(IRouteEndpoint endpoint)
|
||||
{
|
||||
this.RouteEndpoint = endpoint;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITreeRouteBuilder Segment(Func<ITreeSegment> segmentBuilder)
|
||||
{
|
||||
return new TreeRouteBuilder(segmentBuilder, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
public static class TreeRouteBuilderExtensions
|
||||
{
|
||||
public static ITreeRouteBuilder Path(this ITreeRouteBuilder routeBuilder, string path)
|
||||
{
|
||||
ITreeRouteBuilder current = routeBuilder;
|
||||
foreach (var segment in path.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
current = current.Segment(() => new PathSegment(segment));
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
public static ITreeRouteBuilder Parameter(this ITreeRouteBuilder routeBuilder, string name)
|
||||
{
|
||||
return routeBuilder.Segment(() => new ParameterSegment(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Routing.Tree
|
||||
{
|
||||
public static class TreeRouteExtensions
|
||||
{
|
||||
public static ITreeRouteBuilder AddTreeRoute(this IRouteBuilder routeBuilder)
|
||||
{
|
||||
return new TreeRouteBuilder(routeBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,7 @@
|
|||
"version": "0.1-alpha-*",
|
||||
"dependencies": {},
|
||||
"configurations": {
|
||||
"net45": {
|
||||
"dependencies": {
|
||||
"Owin": "1.0",
|
||||
"Microsoft.Owin": "2.1.0"
|
||||
}
|
||||
},
|
||||
"net45": { },
|
||||
"k10" : { }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue