2015/12/2

MVC 中「找到多個與名稱為'Home' 的控制器相符的型別」問題

今天在建立一個新的 MVC5 專案後, 突然發生了「找到多個與名稱為'Home' 的控制器相符的型別」的奇怪問題...

MVC 中「找到多個與名稱為'Home' 的控制器相符的型別」問題

這個問題的描述很明確, 為什麼我說它很奇怪呢? 首先, 如上圖, STOCK 和 CUSTSERV 這是兩個完全不相干的網站。它們既不屬於同一個方案, 它們的檔案甚至處於不同的資料夾裡。因此, 為什麼在 STOCK 專案裡的 MVC 網站會找到 CUSTSERV 的 HomeController? 這真是完全說不通的。

不過, 我回想了一下, 當我剛建立好 STOCK 專案時, 這個問題明明不存在的! 但是我後來做了一件事, 問題就發生了。

我曾經把 CUSTSERV 專案拉到方案裡, 並且在 STOCK 專案中把它加入參考, 後來發現不需要, 於是將它從方案中移除, 再從 STOCK 專案裡把它從參考中移除。一般來講, 我們也許以為這樣就夠了, 其實不然。MVC 仍然能夠找到不在方案裡、也不在參考裡的其它專案的 Controller。原因稍後再說。

稍加研究之後, 我找到兩個解法如下。

解法一

如同錯誤訊息裡的提示, 我們可以在 MVC 專案中 App_Start 資料夾裡找到 RouteConfig.cs 這個類別。將這個類別中唯一的方法修改如下:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        namespaces: new[] { "STOCK.Controllers" }, 
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

在這裡, 只有 namespaces: new[] { "STOCK.Controllers" }, 這一行是修改過的。換句話說, 在 RouteCollectionExtensions.MapRount() 這個擴充方法裡加上 namespaces 參數, 就可以讓 MapRount() 方法只搜尋特定 namespace 之下的 controller。如此一來, 它就不會搜尋其它 namespace 之下的 controller 了。

解法二

更簡單的方法, 就是把專案中 bin 資料夾裡不需要的檔案砍掉。如上所述, 當你曾經把其它專案加入參考後, Visual Studio 會自動幫你把該專案的 .dll 等檔案拷貝到 bin 子目錄之下。而上面提到的 MapRount() 方法會去搜尋這裡所有可能的 controller。這就是本問題最主要的原因。

在我的案例中, 當我把 bin 資料夾中 CUSTSERV.dll 與 CUSTSERV.pdb 兩個檔案刪除之後, 問題就解決了, 不需要採用解法一裡描述的做法。

我們一般都會忽略掉 bin 資料夾裡的檔案, 因為 Visual Studio 在方案總管中預設是不顯示這個資料夾以及其下所有檔案的。你可以在方案總管中打開「顯示所有檔案」選項:

在方案總管中顯示所有檔案然後你就可以在這裡進行檔案操作了。

可惜的是, 我後來在我方案中加入了另一個獨立的類別庫專案, 它也參考了 CUSTSERV。在這情況下, STOCK 網站仍然能夠找到 CUSTSERV 之下的 HomeController。所以我可以推測 MVC 會在整個方案中搜尋所有可能的 Controller。看來 MVC 似乎採用了完全沒有 boundary 的搜尋法。我不知道為什麼它會這樣設計, 也不知該如何才能定義它的 scope。

不管如何, 如果你的方案並不是太複雜的話, 採用解法一就已經足夠了。

沒有留言:

張貼留言