A path segment that contains more than one section, such as a literal section or a parameter, cannot contain a catch-all parameter. Parameter name: routeUrl
2011-11-18 16:09 symphony2010 阅读(1128) 评论(0) 编辑 收藏 举报出错的原因是 “*/{*catchall}”有两个星号,但是为了追寻.net抛出异常的路径下面对其进行源码分析。
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"myRoute",
"{controller}/{aciton}/{id}/*{*catchall}",
new { controller = "Home", action = "index", id = UrlParameter.Optional },
new { controller="^H.*",action="Index|Action",httpMethod=new HttpMethodConstraint("GET","POST"),customConstraint=new UserAgentConstraint("IE")}
);
堆栈信息如下:
System.Web.Routing.RouteParser.Parse(String routeUrl) +2346369
System.Web.Routing.Route..ctor(String url, IRouteHandler routeHandler) +12
System.Web.Mvc.RouteCollectionExtensions.IgnoreRoute(RouteCollection routes, String url, Object constraints) +59
System.Web.Mvc.RouteCollectionExtensions.IgnoreRoute(RouteCollection routes, String url) +6 MVCRouting.MvcApplication.RegisterRoutes(RouteCollection routes) in E:\MVCRouting\MVCRouting\Global.asax.cs:35
MVCRouting.MvcApplication.Application_Start() in E:\MVCRouting\MVCRouting\Global.asax.cs:55
错误在Parse时抛出异常:
RouteParser.Parse(string routeUrl)源码如下:
public static ParsedRoute Parse(string routeUrl) { if (routeUrl == null) { routeUrl = string.Empty; } if ((routeUrl.StartsWith("~", StringComparison.Ordinal) || routeUrl.StartsWith("/", StringComparison.Ordinal)) || (routeUrl.IndexOf('?') != -1)) { throw new ArgumentException(SR.GetString("Route_InvalidRouteUrl"), "routeUrl"); } IList<string> pathSegments = SplitUrlToPathSegmentStrings(routeUrl); Exception exception = ValidateUrlParts(pathSegments);//错误在此行被抛出,下面单步跟踪此函数进行分析 if (exception != null) { throw exception; } return new ParsedRoute(SplitUrlToPathSegments(pathSegments)); }
根据源码分析可知:以~或者是/,或者包含有?的都会被过滤掉,并抛出一下异常:
Route_InvalidRouteUrl=The route URL cannot start with a '/' or '~' character and it cannot contain a '?' character.
SplitUrlToPathSegmentStrings将URL转换为List<string> 的形式,异常不会在此抛出。所以分析ValidateUrlParts。
分析 ValidateUrlParts源代码:
private static Exception ValidateUrlParts(IList<string> pathSegments)
{
HashSet<string> usedParameterNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
bool? nullable = null;
bool flag = false;
foreach (string str in pathSegments)//在foreach循环里面进行真正的有效性验证
{
bool flag2;
if (flag)
{
return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("Route_CatchAllMustBeLast"), new object[0]), "routeUrl");
}
if (!nullable.HasValue)
{
nullable = new bool?(IsSeparator(str));
flag2 = nullable.Value;
}
else
{
flag2 = IsSeparator(str);//判断是否为“/”
if (flag2 && nullable.Value)
{
return new ArgumentException(System.Web.SR.GetString("Route_CannotHaveConsecutiveSeparators"), "routeUrl");
}
nullable = new bool?(flag2);
}
if (!flag2)
{
Exception exception;
IList<PathSubsegment> pathSubsegments = ParseUrlSegment(str, out exception);
/*
PathSubSegment:有一个空的抽象类
*/
if (exception != null)
{
return exception;
}
exception = ValidateUrlSegment(pathSubsegments, usedParameterNames, str);
if (exception != null)
{
return exception;
}
flag = Enumerable.Any<PathSubsegment>(pathSubsegments, delegate (PathSubsegment seg) {
return (seg is ParameterSubsegment) && ((ParameterSubsegment) seg).IsCatchAll;
});
}
}
return null;
}
异常应该在ValidateURlSegment里面抛出,所以分析 其源码如下:
private static Exception ValidateUrlSegment(IList<PathSubsegment> pathSubsegments, HashSet<string> usedParameterNames, string pathSegment)
{
bool flag = false;
Type type = null;
//循环遍历pathSubsegments,关于PathSubsegment,ContentPathSegment……,详细信息看以下链接:http://www.cnblogs.com/Wind-Eagle/archive/2008/12/05/1348645.html
foreach (PathSubsegment subsegment in pathSubsegments)
{
if ((type != null) && (type == subsegment.GetType()))//
{
return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("Route_CannotHaveConsecutiveParameters"), new object[0]), "routeUrl");
}
type = subsegment.GetType();
if (!(subsegment is LiteralSubsegment))
{
ParameterSubsegment subsegment3 = subsegment as ParameterSubsegment;
if (subsegment3 != null)
{
string parameterName = subsegment3.ParameterName;
if (subsegment3.IsCatchAll)
{
flag = true;
}
if (!IsValidParameterName(parameterName))
{
return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("Route_InvalidParameterName"), new object[] { parameterName }), "routeUrl");
}
if (usedParameterNames.Contains(parameterName))
{
return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("Route_RepeatedParameter"), new object[] { parameterName }), "routeUrl");
}
usedParameterNames.Add(parameterName);
}
}
}
if (flag && (pathSubsegments.Count != 1))//在什么情况下此条件为TRUE呢?
//例如:/*{*catchall},第一个*为一个LiteralSubsegment,而后面紧接着就是一个catchall(判断并不是以catchall文字为标准,而是开头是否为*)占位符.
{
//这里便是抛出异常的代码行!!!
return new ArgumentException(string.Format(CultureInfo.CurrentUICulture, System.Web.SR.GetString("Route_CannotHaveCatchAllInMultiSegment"), new object[0]), "routeUrl");
}
return null;
}
最终找到抛出异常的代码行。