使用Areas

MVC Framework支持将一个web application放入一个area,每个area表示一个特殊功能的应用程序片段,比如管理,账单,客户支持等等。这对大型项目很有用,如果大型项目中所有的controller,View和model都只有相应的一个文件夹,那么很难管理,那么此时使用area会很有帮助。

每个MVC有它自己的目录结构,允许你将任何大型隔离。这让多个开发人员开发同一个项目时不产生冲突。Area通过路由系统支持。下面我们会介绍如何建立和使用area。

我们使用Internet Application模板创建一个新的的MVC项目,命名为WorkingWithAreas。

创建Area

在MVC应用程序中增加area,邮件点击项目,选择增加Add Area。Visual Studio会提示输入area名,如下图。这里,我们创建一个area,命名为Admin。这是一个非常常用的area,因为很多web application需要隔离面向客户的功能和管理的功能。

clipboard

点击Add,会发现项目中增加了一个命名为Areas的文件夹,其中包含一个Admin文件夹,表示我们刚刚创建的Area。如果我们创建额外的area,其他的文件夹也会创建在这里。

在Admin文件夹下,你会发现有个小型的MVC项目。里面有Controllers,Models和Views文件夹。前两个是空文件夹,Views文件夹包含一个Shared文件夹和 Web.config( Web.config配置view engine,此处不讨论,后续会说到。)。还有生成了一个AdminAreaRegistration 类。AdminAreaRegistration类如下:

namespace WorkingWithAreas.Areas.Admin

{

    public class AdminAreaRegistration : AreaRegistration

    {

        public override string AreaName

        {

            get

            {

                return "Admin";

            }

        }

        public override void RegisterArea(AreaRegistrationContext context)

        {

            context.MapRoute(

            "Admin default",

            "Admin/{controller}/{action}/{id}",

            new { action = "Index", id = UrlParameter.Optional }

            );

        }

    }

}

这里需要关注的是RegisterArea方法。此方法使用URL模式Admin/{controller}/{action}/{id}注册路由。我们可以在此方法中定义额外的路由。

注意,如果你命名了你路由,你必须保证这个命名在整个应用程序中是唯一的,而不是仅仅在area中。

我们不需要做什么来保证这个注册方法能被调用,Global.asax的Application Start 方法自动帮我们处理了。如下:

protected void Application Start() {

AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);

    RegisterRoutes(RouteTable.Routes);

}

静态方法 AreaRegistration.RegisterAllAreas能使MVC Framework遍历我们应用程序中的所有的类,找出那些继承于AreaRegistration类的子类,调用他们的RegisterArea方法。

注意,不要改变 Application Start方法中有关路由语句的顺序。如果你在调用AreaRegistration前调用RegisterRoutes,那么你的路由在area routes路由之前被拒绝。

传递给每个area的RegisterArea方法的AreaRegistrationContext类提供了一组MapRoute方法,通过该方法,area可以用和主程序相同的方法注册routes。

注意,AreaRegistrationContext类中的MapRoute方法自动限制你注册命名空间,这意味当你在area创建controller,你必须使用它默认的命名空间,不然路由系统找不到他。


加入到Area

如之前的例子,你可以在area中创建controller,view和model。创建controller,只需要右键点击Controller文件夹,选择Add Controller,输入名字。

clipboard[1]

此例中我们增加一个HomeController。

using System.Web.Mvc;

namespace WorkingWithAreas.Areas.Admin.Controllers {

    public class HomeController : Controller {

    public ActionResult Index() {

        return View();

    }

    }

}

为了完成这个例子,我们为Homecontroller的Index方法通过点击右键创建view,使用默认的名字Index。一旦创建完毕,你会发现在 Areas/Admin/Views/Home目录下的view。view的代码如下:

@{

    ViewBag.Title = "Index";

}

<h2>Admin Area Index</h2>

这个例子可以看到,area中的工作方式和在MVC项目的主项目是一样的,如果输入导航/Admin/Home/Index,会看到如下界面:

clipboard[2]

解决Controller混淆的问题

之前,我们撒了一点小谎,先前的例子,如果你导航到application的跟URL,会出现一个错误,和之前的错误很相似。

clipboard[3]

When an area is registered, any routes that we define are limited to the namespace associated with the area. This is how we were able to request /Admin/Home/Index and get the HomeController class in the

WorkingWithAreas.Areas.Admin.Controllers namespace.

However, routes defined in the RegisterRoutes method of Global.asax are not similarly restricted.

You can see the default routing configuration that Visual Studio puts in place in Listing 11-53.

当一个area注册了,我们定义的任何路由都限制了命名空间和area的关联。所以我们这样请求 /Admin/Home/Index,并且在WorkingWithAreas.Areas.Admin.Controllers 命名空间获得HomeController类。但是, Global.asax中RegisterRoutes 方法中的路由定义却没有被限制,如下,你可以看到默认的路由配置:

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 }

    );

}

名称为Default的路由把浏览器发来的URL转换成Home controller的Index action。在此,我们得到一个error,因为,此处没有命名空间限制路由,MVC Framework可以看到2个HomeController。要解决这种问题,我们需要给Global.asax中的主controller命名空间以优先权。如下:

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 },

new[] {"WorkingWithAreas.Controllers"}

);

}

这个修改保证了主项目中的controller获得了优先权。当然,你也可以给area中的controller优先权。

在Area中生成为Action生成Link

You don’t need to take any special steps to create links that refer to actions in the same MVC area that

the user is already on. The MVC Framework detects that the current request relates to a particular area,

and then outbound URL generation will find a match only among routes defined for that area. For

example, this addition to the view in our Admin area:

Area中不需要特殊的步骤创建link,就如同在MVC中一样。MVC Framework发现当前请求与某个area有关,然后会在area里定义的路由中找到一个匹配来生成URL。比如:

@Html.ActionLink("Click me", "About")

生成如下的html

<a href="/Admin/Home/About">Click me</a>

要创建不同area中的action的link,你必须创建一个area变量,使用它设置你需要的area的名字,比如:

@Html.ActionLink("Click me to go to another area", "Index", new { area = "Support" })

这也是为什么area也是片段变量名的保留字。HTML由调用生成的HTML如下:

<a href="/Support/Home">Click me to go to another area</a>

如果你想链接到一个top-level controllers的action(在 /Controllers目录中的controller),那么你需要知道area为空字符串,就像:

@Html.ActionLink("Click me to go to another area", "Index", new { area = "" })