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:
Ryan Nowak 2014-01-28 14:26:58 -08:00
parent 4183bc98be
commit c0660f347a
47 changed files with 1 additions and 3229 deletions

63
.gitattributes vendored
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +0,0 @@

using System.Collections.Generic;
namespace Microsoft.AspNet.Routing
{
public interface IRoute
{
BoundRoute Bind(RouteBindingContext context);
RouteMatch GetMatch(RoutingContext context);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,12 +2,7 @@
"version": "0.1-alpha-*",
"dependencies": {},
"configurations": {
"net45": {
"dependencies": {
"Owin": "1.0",
"Microsoft.Owin": "2.1.0"
}
},
"net45": { },
"k10" : { }
}
}