ASP.NET MVC中Area的另一種用法


【摘要】本文只是為一行代碼而分享

context.MapRoute("API", "api/{controller}/{action}", new { }, newstring[] { "CNBlogs.UcHome.Web.Controllers.Api" });

我們在ASP.NET MVC中使用Area時通常這么干:

在Web項目中創建Areas文件夾,在其中創建對應的Area文件夾,在其下創建Controllers文件夾。然后在Area文件夾中創建AreaRegistration的子類用於注冊Area路由,在Controllers文件夾中創建所需的Controller。

這么干有個前提,就是你的Web項目類型要是WebApplication。

而我們所處的場景是:Web項目類型是WebSite。之前在使用MVC時,將所有的Controller放在了一個單獨的類庫項目中。 

我們今天有一個需求,需要用area來解決。為什么要用area?舉個例子來說明。

比如我們在頁面中添加網摘時,訪問的網址是 home.cnblogs.com/wz/add ,而供其他應用調用網摘API的網址是 home.cnblogs.com/api/wz/add 。這里的wz對應的控制器名稱都是WzController,Action都是add,實際也的確存在兩個WzController,放在不同的文件夾中。如上圖,一個在項目根文件夾,一個在Api文件夾。所以在網址中通過api前綴路徑來區分,在程序中也要讓ASP.NET路由找到對應的Controller。

這時Area就發揮作用了,但由於Conroller不在Web項目中,所以要找其他方法解決這個問題。方法來自Migrating a large web application to ASP.NET MVC(關鍵在最后一行代碼):

When AreaRegistration.RegisterAllAreas() is called, ASP.NET will search for all AreaRegistration subclasses in all assemblies in the bin dir so that we do not have to modify the global.asax when we add new areas.

In the AreaRegistration subclass, we would do something like:

public override void RegisterArea(AreaRegistrationContext context)
{
    context.MapRoute(
    "Services",
    "Sub1/Sub11/Sub111/{controller}.mvc/{action}/{id}",
    new { action = "Index", id = "" },
    new string[] { "My.Custom.Namespace.Controllers" }
    );
}

AreaRegistration.RegisterAllAreas()是global.asax中調用的,它會找到所有的AreaRegistration的子類,不管是在Web項目中,還是在其他類庫項目中。所以我們在CNBlogs.UcHome.Web.Controllers項目的Api文件夾中放一個AreaRegistration的子類,也是能被找到的,然后在注冊Area時,在參數中傳遞Controller所在的命名空間,問題就解決了。

【更新】

雖然通過ApiArea解決了api的路由問題,但是這時我們訪問非api的路徑(比如/wz/my),出現下面的錯誤:

Multiple types were found that match the controller named 'wz'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.

The request for 'wz' has found the following matching controllers:
CNBlogs.UcHome.Web.Controllers.Api.WzController
CNBlogs.UcHome.Web.Controllers.WzController

也就是說,如果有兩個同名的Controller,必須在路由時指定命名空間,routes.MapRoute的第5個參數就是用於指定命名空間,我開始時不知道有這個參數,於是試圖用Area來解決問題,實際是一個錯誤的解決方法,正確的解決方法是在Global.asax中針對不同的命名添加兩個不同的路由,示例代碼如下:

routes.MapRoute("API",
    "api/{controller}/{action}",
    new { },
    null,
    new string[] { "CNBlogs.UcHome.Web.Controllers.Api" }
);

routes.MapRoute("DefaultMvc",
    "{controller}/{action}/{id}",
    new { id = UrlParameter.Optional },
    null,
    new string[] { "CNBlogs.UcHome.Web.Controllers" }
);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM