diff --git a/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs
index a37cb32044..cbfe5d98cd 100644
--- a/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Routing/Properties/Resources.Designer.cs
@@ -10,6 +10,38 @@ namespace Microsoft.AspNet.Routing
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Routing.Resources", typeof(Resources).GetTypeInfo().Assembly);
+ ///
+ /// A default handler must be set on the RouteCollection.
+ ///
+ internal static string DefaultHandler_MustBeSet
+ {
+ get { return GetString("DefaultHandler_MustBeSet"); }
+ }
+
+ ///
+ /// A default handler must be set on the RouteCollection.
+ ///
+ internal static string FormatDefaultHandler_MustBeSet()
+ {
+ return GetString("DefaultHandler_MustBeSet");
+ }
+
+ ///
+ /// The constraint entry '{0}' must have a string value or be of a type which implements '{1}'.
+ ///
+ internal static string GeneralConstraints_ValidationMustBeStringOrCustomConstraint
+ {
+ get { return GetString("GeneralConstraints_ValidationMustBeStringOrCustomConstraint"); }
+ }
+
+ ///
+ /// The constraint entry '{0}' must have a string value or be of a type which implements '{1}'.
+ ///
+ internal static string FormatGeneralConstraints_ValidationMustBeStringOrCustomConstraint(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("GeneralConstraints_ValidationMustBeStringOrCustomConstraint"), p0, p1);
+ }
+
///
/// A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter.
///
@@ -18,6 +50,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_CannotHaveCatchAllInMultiSegment"); }
}
+ ///
+ /// A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter.
+ ///
+ internal static string FormatTemplateRoute_CannotHaveCatchAllInMultiSegment()
+ {
+ return GetString("TemplateRoute_CannotHaveCatchAllInMultiSegment");
+ }
+
///
/// A path segment cannot contain two consecutive parameters. They must be separated by a '/' or by a literal string.
///
@@ -26,6 +66,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_CannotHaveConsecutiveParameters"); }
}
+ ///
+ /// A path segment cannot contain two consecutive parameters. They must be separated by a '/' or by a literal string.
+ ///
+ internal static string FormatTemplateRoute_CannotHaveConsecutiveParameters()
+ {
+ return GetString("TemplateRoute_CannotHaveConsecutiveParameters");
+ }
+
///
/// The route template separator character '/' cannot appear consecutively. It must be separated by either a parameter or a literal value.
///
@@ -34,6 +82,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_CannotHaveConsecutiveSeparators"); }
}
+ ///
+ /// The route template separator character '/' cannot appear consecutively. It must be separated by either a parameter or a literal value.
+ ///
+ internal static string FormatTemplateRoute_CannotHaveConsecutiveSeparators()
+ {
+ return GetString("TemplateRoute_CannotHaveConsecutiveSeparators");
+ }
+
///
/// A path segment that contains more than one section, such as a literal section or a parameter, cannot contain an optional parameter.
///
@@ -42,6 +98,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_CannotHaveOptionalParameterInMultiSegment"); }
}
+ ///
+ /// A path segment that contains more than one section, such as a literal section or a parameter, cannot contain an optional parameter.
+ ///
+ internal static string FormatTemplateRoute_CannotHaveOptionalParameterInMultiSegment()
+ {
+ return GetString("TemplateRoute_CannotHaveOptionalParameterInMultiSegment");
+ }
+
///
/// A catch-all parameter cannot be marked optional.
///
@@ -50,6 +114,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_CatchAllCannotBeOptional"); }
}
+ ///
+ /// A catch-all parameter cannot be marked optional.
+ ///
+ internal static string FormatTemplateRoute_CatchAllCannotBeOptional()
+ {
+ return GetString("TemplateRoute_CatchAllCannotBeOptional");
+ }
+
///
/// A catch-all parameter can only appear as the last segment of the route template.
///
@@ -58,6 +130,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_CatchAllMustBeLast"); }
}
+ ///
+ /// A catch-all parameter can only appear as the last segment of the route template.
+ ///
+ internal static string FormatTemplateRoute_CatchAllMustBeLast()
+ {
+ return GetString("TemplateRoute_CatchAllMustBeLast");
+ }
+
///
/// The literal section '{0}' is invalid. Literal sections cannot contain the '?' character.
///
@@ -66,6 +146,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_InvalidLiteral"); }
}
+ ///
+ /// The literal section '{0}' is invalid. Literal sections cannot contain the '?' character.
+ ///
+ internal static string FormatTemplateRoute_InvalidLiteral(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TemplateRoute_InvalidLiteral"), p0);
+ }
+
///
/// The route parameter name '{0}' is invalid. Route parameter names must be non-empty and cannot contain these characters: '{{', '}}', '/'. The '?' character marks a parameter as optional, and can only occur at the end of the parameter.
///
@@ -74,6 +162,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_InvalidParameterName"); }
}
+ ///
+ /// The route parameter name '{0}' is invalid. Route parameter names must be non-empty and cannot contain these characters: '{{', '}}', '/'. The '?' character marks a parameter as optional, and can only occur at the end of the parameter.
+ ///
+ internal static string FormatTemplateRoute_InvalidParameterName(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TemplateRoute_InvalidParameterName"), p0);
+ }
+
///
/// The route template cannot start with a '/' or '~' character.
///
@@ -82,6 +178,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_InvalidRouteTemplate"); }
}
+ ///
+ /// The route template cannot start with a '/' or '~' character.
+ ///
+ internal static string FormatTemplateRoute_InvalidRouteTemplate()
+ {
+ return GetString("TemplateRoute_InvalidRouteTemplate");
+ }
+
///
/// There is an incomplete parameter in the route template. Check that each '{' character has a matching '}' character.
///
@@ -90,6 +194,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_MismatchedParameter"); }
}
+ ///
+ /// There is an incomplete parameter in the route template. Check that each '{' character has a matching '}' character.
+ ///
+ internal static string FormatTemplateRoute_MismatchedParameter()
+ {
+ return GetString("TemplateRoute_MismatchedParameter");
+ }
+
///
/// The route parameter name '{0}' appears more than one time in the route template.
///
@@ -98,6 +210,14 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_RepeatedParameter"); }
}
+ ///
+ /// The route parameter name '{0}' appears more than one time in the route template.
+ ///
+ internal static string FormatTemplateRoute_RepeatedParameter(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TemplateRoute_RepeatedParameter"), p0);
+ }
+
///
/// The constraint entry '{0}' on the route with route template '{1}' must have a string value or be of a type which implements '{2}'.
///
@@ -106,15 +226,26 @@ namespace Microsoft.AspNet.Routing
get { return GetString("TemplateRoute_ValidationMustBeStringOrCustomConstraint"); }
}
- private static string GetString(string name, params string[] argumentNames)
+ ///
+ /// The constraint entry '{0}' on the route with route template '{1}' must have a string value or be of a type which implements '{2}'.
+ ///
+ internal static string FormatTemplateRoute_ValidationMustBeStringOrCustomConstraint(object p0, object p1, object p2)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("TemplateRoute_ValidationMustBeStringOrCustomConstraint"), p0, p1, p2);
+ }
+
+ private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
-
- for (var i = 0; i < argumentNames.Length; i++)
+
+ if (formatterNames != null)
{
- value = value.Replace("{" + argumentNames[i] + "}", "{" + i + "}");
+ for (var i = 0; i < formatterNames.Length; i++)
+ {
+ value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
+ }
}
return value;
diff --git a/src/Microsoft.AspNet.Routing/Resources.resx b/src/Microsoft.AspNet.Routing/Resources.resx
index 5fa396065a..b7bd0bf538 100644
--- a/src/Microsoft.AspNet.Routing/Resources.resx
+++ b/src/Microsoft.AspNet.Routing/Resources.resx
@@ -117,6 +117,12 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ A default handler must be set on the RouteCollection.
+
+
+ The constraint entry '{0}' must have a string value or be of a type which implements '{1}'.
+
A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter.
diff --git a/src/Microsoft.AspNet.Routing/RouteCollectionExtensions.cs b/src/Microsoft.AspNet.Routing/RouteCollectionExtensions.cs
index 6bdb326628..a5cfdf9db3 100644
--- a/src/Microsoft.AspNet.Routing/RouteCollectionExtensions.cs
+++ b/src/Microsoft.AspNet.Routing/RouteCollectionExtensions.cs
@@ -10,35 +10,38 @@ namespace Microsoft.AspNet.Routing
{
public static IRouteCollection MapRoute(this IRouteCollection routes, string template)
{
- MapRoute(routes, template, null);
+ MapRoute(routes, template, defaults: null);
return routes;
}
- public static IRouteCollection MapRoute(this IRouteCollection routes, string template, object defaults)
+ public static IRouteCollection MapRoute(this IRouteCollection routes, string template,
+ object defaults)
{
MapRoute(routes, template, new RouteValueDictionary(defaults));
return routes;
}
- public static IRouteCollection MapRoute(this IRouteCollection routes, string template, IDictionary defaults)
+ public static IRouteCollection MapRoute(this IRouteCollection routes, string template,
+ IDictionary defaults)
{
if (routes.DefaultHandler == null)
{
- throw new ArgumentException("DefaultHandler must be set.");
+ throw new InvalidOperationException(Resources.DefaultHandler_MustBeSet);
}
- routes.Add(new TemplateRoute(routes.DefaultHandler, template, defaults, null));
+ routes.Add(new TemplateRoute(routes.DefaultHandler, template, defaults, constraints: null));
return routes;
}
- public static IRouteCollection MapRoute(this IRouteCollection routes, string template, object defaults, object constraints)
+ public static IRouteCollection MapRoute(this IRouteCollection routes, string template,
+ object defaults, object constraints)
{
MapRoute(routes, template, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints));
return routes;
}
- public static IRouteCollection MapRoute(this IRouteCollection routes, string template, object defaults,
- IDictionary constraints)
+ public static IRouteCollection MapRoute(this IRouteCollection routes, string template,
+ object defaults, IDictionary constraints)
{
MapRoute(routes, template, new RouteValueDictionary(defaults), constraints);
return routes;
@@ -56,7 +59,7 @@ namespace Microsoft.AspNet.Routing
{
if (routes.DefaultHandler == null)
{
- throw new ArgumentException("DefaultHandler must be set.");
+ throw new InvalidOperationException(Resources.DefaultHandler_MustBeSet);
}
routes.Add(new TemplateRoute(routes.DefaultHandler, template, defaults, constraints));
diff --git a/src/Microsoft.AspNet.Routing/RouteConstraintBuilder.cs b/src/Microsoft.AspNet.Routing/RouteConstraintBuilder.cs
index 625cfad237..c7383b1406 100644
--- a/src/Microsoft.AspNet.Routing/RouteConstraintBuilder.cs
+++ b/src/Microsoft.AspNet.Routing/RouteConstraintBuilder.cs
@@ -5,8 +5,20 @@ namespace Microsoft.AspNet.Routing
{
public class RouteConstraintBuilder
{
- public static IDictionary
+ public static IDictionary
BuildConstraints(IDictionary inputConstraints)
+ {
+ return BuildConstraintsCore(inputConstraints, routeTemplate: null);
+ }
+
+ public static IDictionary
+ BuildConstraints(IDictionary inputConstraints, [NotNull] string routeTemplate)
+ {
+ return BuildConstraintsCore(inputConstraints, routeTemplate);
+ }
+
+ public static IDictionary
+ BuildConstraintsCore(IDictionary inputConstraints, string routeTemplate)
{
if (inputConstraints == null || inputConstraints.Count == 0)
{
@@ -25,7 +37,18 @@ namespace Microsoft.AspNet.Routing
if (regexPattern == null)
{
- throw new InvalidOperationException("Constraint can be a valid regex string or an IRouteConstraint");
+ if (routeTemplate != null)
+ {
+ throw new InvalidOperationException(
+ Resources.FormatTemplateRoute_ValidationMustBeStringOrCustomConstraint(
+ kvp.Key, routeTemplate, typeof (IRouteConstraint)));
+ }
+ else
+ {
+ throw new InvalidOperationException(
+ Resources.FormatGeneralConstraints_ValidationMustBeStringOrCustomConstraint(
+ kvp.Key, typeof(IRouteConstraint)));
+ }
}
var constraintsRegEx = "^(" + regexPattern + ")$";
diff --git a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
index 6f9c2fc22a..acf6c22e50 100644
--- a/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
+++ b/src/Microsoft.AspNet.Routing/Template/TemplateRoute.cs
@@ -20,18 +20,13 @@ namespace Microsoft.AspNet.Routing.Template
{
}
- public TemplateRoute(IRouter target, string routeTemplate, IDictionary defaults,
+ public TemplateRoute([NotNull] IRouter target, string routeTemplate, IDictionary defaults,
IDictionary constraints)
{
- if (target == null)
- {
- throw new ArgumentNullException("target");
- }
-
_target = target;
_routeTemplate = routeTemplate ?? string.Empty;
_defaults = defaults ?? new Dictionary(StringComparer.OrdinalIgnoreCase);
- _constraints = RouteConstraintBuilder.BuildConstraints(constraints);
+ _constraints = RouteConstraintBuilder.BuildConstraints(constraints, _routeTemplate);
// The parser will throw for invalid routes.
var parsedTemplate = TemplateParser.Parse(RouteTemplate);
@@ -50,13 +45,8 @@ namespace Microsoft.AspNet.Routing.Template
get { return _routeTemplate; }
}
- public async virtual Task RouteAsync(RouteContext context)
+ public async virtual Task RouteAsync([NotNull] RouteContext context)
{
- if (context == null)
- {
- throw new ArgumentNullException("context");
- }
-
var requestPath = context.RequestPath;
if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
{