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" }
);

 

posted @ 2012-12-14 11:33  dudu  阅读(25023)  评论(16编辑  收藏  举报