1. 程式人生 > >MVC自定義路由,實現二級域名類導致的找到多個與名為xxx的控制器匹配的型別的錯誤

MVC自定義路由,實現二級域名類導致的找到多個與名為xxx的控制器匹配的型別的錯誤

今日在網站錯誤日誌中發現手機站頁面訪問:http://m.jinrimianshi.com/company/395961

時出現找到多個與名為“company”的控制器匹配的型別。如果為此請求(“{controller}/{action}/{id}”)提供服務的路由沒有指定名稱空間以搜尋與此請求相匹配的控制器,則會發生這種情況。如果是這樣,請通過呼叫帶有 'namespaces' 引數的 "MapRoute" 方法的過載來註冊此路由的錯誤。

“company”請求找到下列匹配的控制器:

LMCMS.Areas.Admin.Controllers.CompanyController

LMSoft.Zhaopin.Controllers.CompanyController

由於我沒有使用namespaces引數,而有如果出現多個匹配,可以使用namespaces引數的maproute方法過載來註冊此路由的提示。我進行了重寫。重寫後是這樣得:

//自定義路由 
routes.Add("DomainRouteForManage"new DomainRoute(
     "m.jinrimianshi.com",                      // 固定的二級域名
     "{controller}/{action}/{id}",                  // URL with parameters
     new                               //defaults
     {         area = "M",         controller = "Home",         action = "Index",         id = UrlParameter.Optional,         Namespaces = new string[] { "LMSoft.Zhaopin.Areas.M.Controllers" }       }  // Parameter defaults ));

但是編譯重新整理後問題依舊,沒起什麼作用。這時我想知道這個路由究竟是如何匹配的。由於以前處理路由匹配的時候知道有一個routedebugger工具可以查匹配情況。因此先裝此工具。

首先在程式包控制檯中執行命令

Install-Package routedebugger

執行後web.config中出現了一行程式碼:

<addkey="RouteDebugger:Enabled"value="true" />

然後編譯重新整理專案,但是在頁面底部並沒有出現routedebugger的路由提示資訊。經過分析,發現專案中缺少了對routedebugger的dll引用。在專案的packages包中找到routedebugger.dll,在專案中新增對其的引用。新增後編譯,重新整理專案,路由資訊出現了。


通過檢視,有4個匹配項。綠色為true的。由於我們知道mvc的路由匹配機制是從上往下尋找。當找到第一個匹配的時候就跳轉到這個匹配規則上執行。下面的其他匹配被放棄。通過下圖可以看出,確實匹配的是名字為DomainRouteForManage的自定義路由。可是已經限制了這個controller的名稱空間為:LMSoft.Zhaopin.Areas.M.Controllers,怎麼沒起作用?


通過大量的查詢資料,終於找到了想要的答案。原來在控制器的啟用過程中,是由DefaultControllerFactory控制的。它首先在你限定的名稱空間中進行查詢,如果找不到相應的控制器,那麼它會看DataTokens["UseNamespaceFallback"]是否有,如果沒有設定,或者有但是值為true,那麼在限定的名稱空間中找不到相應的控制器的情況下,它會搜尋專案中其他名稱空間下的控制器,如果出現多個匹配,則就會報找到多個與名為“company”的控制器匹配的型別這樣得錯誤資訊。如果有設定,並且值為false,則在找不到匹配的情況下就會報404錯誤。那對應此次我碰到的錯誤。很顯然,在LMSoft.Zhaopin.Areas.M.Controllers這個我限定的名稱空間沒找到名我company的控制器,而在DataTokens中,UseNamespaceFallback也沒有。所以導致其搜尋了專案其他名稱空間的控制器,找到了兩個匹配,因此出現了此錯誤。知道了錯誤的原因,那麼解決此問題就有了思路。由於我自定義二級域名的路由使用的是一個自寫的類:DomainRoute,此類是在網上找的,網上有相應程式碼,大同小異,我這裡就不寫了。我找到了此類中新增Namespaces的程式碼部分。

foreach (KeyValuePair<stringobject> item in Defaults)
{
     data.Values[item.Key] = item.Value;
#region 此處將area及Namespaces寫入DataTokens裡
     if (item.Key.Equals("area") || item.Key.Equals("Namespaces"))
     {
          data.DataTokens[item.Key] = item.Value;
                            
     }
#endregion
}

data.DataTokens[item.Key] = item.Value;程式碼下面增加了一行程式碼:

data.DataTokens["UseNamespaceFallback"] = false;

由於這個是迴圈新增,加上後我還擔心會不會重複新增UseNamespaceFallback,編譯重新整理後才發現自己多慮了。並沒有重複新增,仍然是一個UseNamespaceFallback。

結果出來了,出現了我想要的,404未發現的錯誤。問題解決

參考文章:

http://www.cnblogs.com/P_Chou/archive/2010/11/15/details-asp-net-mvc-04.html

http://www.cnblogs.com/yipu/archive/2012/11/21/2780119.html