在ASP.NET MVC 中宿主WCF Rest 服务的问题及解决方法
好久没写博客,今天上来看看,都长草了,看来得打扫打扫了。
最近在研究 ASP.NET MVC 3和WCF Reset Service,突然想看看把它们放在一起会怎么样。想到这里动手就干。下面就是我写的代码:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RouteTable.Routes.Add(new ServiceRoute("Uap", new WebServiceHostFactory(), typeof(Service.UapService)));
RegisterRoutes(RouteTable.Routes);
}
}
然后兴冲冲的按下了F5.嗯主页如愿出来了,输入Service的Url,也很正常。看来一切正常。兴奋中。随便点击了个连接。接着杯具出现了。
http://localhost:3315/Uap?action=About&controller=Home 这……这……这是什么地址?我怎么没见过。囧啊。
……
…………
想了半天也没搞清楚到底怎么回事。
检查代码也没法现问题。
<ul id="menu">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("Application", "Index", "Application")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
</ul>
我发誓,这些代码在加入WCF Rest Service之前是正常工作的。
看来是
RouteTable.Routes.Add(new ServiceRoute("Uap", new WebServiceHostFactory(), typeof(Service.UapService)));
这行代码搞的鬼。
我把这行代码放在
RegisterRoutes(RouteTable.Routes);
下面之后发现,连接的URL到是正常了,可WCF Rest Service又不能工作了。真是活见鬼了。
百思不得其果后干脆一不做二不休,下载了MVC的源代码。
在稀里哗啦的一阵F5加F11后,终于发现问题所在了。
原来ActionLink方法在生成Url的时候会轮询所有的Route,要求符合条件的Route生成指定参数的Url并返回第一个生成值,结果蛋疼的ServiceRoute不知道是脑袋烧坏了还是怎么的。给我返回了/Uap?action=About&controller=Home这么个悲催的地址。ActionLink方法就原模原样的给输出到页面了(也不看看是不是上当了,真是个傻二哥)。
看来问题的症结已经找到了。现在该想办法解决了。
最直接的方法就是修改MVC的源代码,不过在看了整个MVC项目的源代码后,我放弃了这个疯狂的想法。
不过到是发现了一个方法,那就是把
RouteTable.Routes.Add(new ServiceRoute("Uap", new WebServiceHostFactory(), typeof(Service.UapService)));
放在所有MVC的Route之后所有连接的Url就都正常了。
可是这样WCF Rest Service的Route地址就会被
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
拦截。
头疼……
看来得想办法让MVC 的Route忽略ServiceRoute的Route地址。该怎么做呢。
忽略?对,忽略!
说做就做。
routes.IgnoreRoute("/Uap/{*pathInfo}");
这下应该可以了吧?
按下F5,首页正常;链接Url正常;Wcf Service?不正常。靠……
仔细看看,靠……
头疼医脚,这个IgnoreRoute和MVC压根就没半毛钱关系。
routes.IgnoreRoute("/Uap/{*pathInfo}");
干脆直接把Wcf Service给封杀了。
看来这样还是不行,难道真的要去修改MVC的源代码吗?
我可不想这么做,再研究研究好了。我宁愿发半个小时的呆也不愿多写一行代码,动手毕竟没有动脑那么有成就感。(一个该被鄙视的懒鬼,发半个小时呆就为了想方设法少写一行代码。)
百无聊赖下翻起了MSDN,突然记起MapRoute方法有一个指定路由规则的参数,这个参数可以传递一个正则表达式来约束路由规则。
看来我已经找到了解决问题的金钥匙了。
于是写如下代码:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { controller = @"^\b(?!uap)\w*\b$" }
规则很简单,忽略所有路径中有uap字符的路径。
运行之后发现,一切正常,终于解决问题。
贴上源代码:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { controller = @"^\b(?!uap)\w*\b$" }
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
RouteTable.Routes.Add(new ServiceRoute("Uap", new WebServiceHostFactory(), typeof(Service.UapService)));
}
}
收工,睡觉。
迷糊中……猛然惊醒,靠……忘了洗澡!!!!!