第一遍检查发现路由重命名
第二遍跟踪路由解析发现命名空间与controller文件不匹配
更改后成功解析
其他解决方案:转载至
原文地址
http://blog.useasp.net/archive/2012/08/07/confused-with-the-MapRoute-constraint-and-IgnoreRoute-method-in-MVC3-route.aspx
近日在使用MVC3进行开发时,碰到要将一个不存在的路径剔除出来,不要在当前的Route中匹配。但是根据官方的方法怎么也没有办法。感觉MapRoute的处理方法相当的怪异。
首先说明下需求:
一个Area: admin
我们有一个路径:admin/system-monitor/state.axd,该路径没有控制器来接管,也没有物理文件,而是有专门的Handler来处理,因此需要将此路径排除匹配。
我们在Global.asax中的配置大概如下:
1
2
3
4
5
6
7
8
|
routes.IgnoreRoute(
"{resource}.axd/{*pathInfo}"
);
routes.MapRoute(
"Default"
,
"{manager}/{controller}/{action}/{id}/{p}"
,
new
{ manager=
"Sino"
, controller =
"Home"
, action =
"Index"
, id = UrlParameter.Optional, p = UrlParameter.Optional },
new
string
[] {
"Sino.Nico.Controllers"
}
);
|
这个是配置前台的路由,问题不大,后台的路由配置:
1
2
3
4
5
6
|
context.MapRoute(
"admin"
,
"admin/{manager}/{controller}/{action}"
,
new
{ manager=
"Sino"
, controller =
"Home"
, action =
"Index"
},
new
string
[] {
"Sino.Nico.Areas.Admin.Controllers"
}
);
|
这两个配置在没有加入排除路径的前提下,运行正常。为了排除路径,我们能想到的最简单的方法就是使用IgnoreRoute了,于是,我们在Global.asax中添加,变成如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
public
static
void
RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute(
"{resource}.axd/{*pathInfo}"
);
routes.IgnoreRoute(
"admin/system-monitor/state.axd/{*pathInfo}"
);
routes.MapRoute(
"Default"
,
"{manager}/{controller}/{action}/{id}/{p}"
,
new
{ manager=
"Sino"
, controller =
"Home"
, action =
"Index"
, id = UrlParameter.Optional, p = UrlParameter.Optional },
new
string
[] {
"Sino.Nico.Controllers"
}
);
}
|
可是这样处理并没有正常的排除掉这个路径,这个路径的访问还是被admin这个Area的路由匹配,结果找不到资源。
MS的官方说,如果使用IgnoreRoute方式来处理后的路径,如果第一时间匹配之后,会直接排除而不会进行任何路由匹配,看来在MVC3中,这个说法好像并不是很确切。 —— 也许是个人理解的出入。为了解决这个问题,我们只能换一种方法来处理,在Area中的RegisterArea方法中创建MapRoute的时候,添加约束,Areas中的代码:
1
2
3
4
5
6
7
8
9
10
11
|
public
override
void
RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"admin"
,
"admin/{manager}/{controller}/{action}"
,
new
{ manager=
"Sino"
, controller =
"Home"
, action =
"Index"
},
new
{ manager=
@"^(?!system-monitor$)"
},
// 使用约束将system-monitor强行不进行匹配
new
string
[] {
"Sino.Nico.Areas.admin.Controllers"
}
);
}
|
注意,这时候我们并没有在Global.asax中添加IgnoreRoute了,遗憾的是,这时候,我们访问的时候,system-monitor匹配到了Global.asax中的路由,直接报没有找到资源。
1
2
3
4
5
6
7
8
9
|
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /admin/system-monitor/
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.272
|
最后,我们只好做两件事情:
1. 我们将路径在Area中直接过滤掉;
2. 在Global.asax中使用IgnoreRoute排除该路径。
这回好了,不再报找不到路径了,但是等我们回过神来,却发现,后台所有的路径都有问题了,都是找不到资源,毫不犹豫肯定是manager的约束出现问题了。正则我们看了又看,肯定是没有问题的,如果manager不为system-monitor的时候,IsMatch肯定是返回true的。
在纠结一段时间之后,我们决定看看MVC内部到底是如何设计的,怎么会出现这种问题,结果,打开代码的那一刹那,我惊了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
protected
virtual
bool
ProcessConstraint(HttpRequestMessage request,
object
constraint,
string
parameterName, HttpRouteValueDictionary values, HttpRouteDirection routeDirection)
{
IHttpRouteConstraint customConstraint = constraint
as
IHttpRouteConstraint;
if
(customConstraint !=
null
)
{
return
customConstraint.Match(request,
this
, parameterName, values, routeDirection);
}
// If there was no custom constraint, then treat the constraint as a string which represents a Regex.
string
constraintsRule = constraint
as
string
;
if
(constraintsRule ==
null
)
{
throw
Error.InvalidOperation(SRResources.Route_ValidationMustBeStringOrCustomConstraint, parameterName, RouteTemplate,
typeof
(IHttpRouteConstraint).Name);
}
object
parameterValue;
values.TryGetValue(parameterName,
out
parameterValue);
string
parameterValueString = Convert.ToString(parameterValue, CultureInfo.InvariantCulture);
string
constraintsRegEx =
"^("
+ constraintsRule +
")$"
;
return
Regex.IsMatch(parameterValueString, constraintsRegEx, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
}
|
原来他自带^(...)$进行头尾匹配!
那么我们的正则再到这里就变成了:^(^(?!system-monitor$))$这个和^(?!system-monitor$)相差也太远了。看到问题了,解决起来就非常简单了。将代码变成如下这样:
1
2
3
4
5
6
7
8
9
10
11
|
public
override
void
RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"admin"
,
"admin/{manager}/{controller}/{action}"
,
new
{ manager=
"Sino"
, controller =
"Home"
, action =
"Index"
},
new
{ manager=
@"(?!system-monitor$)[\w\W]*"
},
// 使用约束将system-monitor强行不进行匹配
new
string
[] {
"Sino.Nico.Areas.admin.Controllers"
}
);
}
|
编译,运行,通过。