代码之家  ›  专栏  ›  技术社区  ›  3Dave

ASP.NET MVC 2 URL/Routes、视图如何与控制器相关?

  •  4
  • 3Dave  · 技术社区  · 15 年前

    有人能解释MVC 2中的路由如何与控制器关联吗?目前,我在/controllers/home controller.cs和view/home/index.aspx中有一个控制器。

    我的路线注册方法如下:

     public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
                routes.MapRoute(
                   "Default",
                    // Route name
                   "{controller}/{action}/{id}",
                    // URL with parameters
                   new { controller = "Home", action = "Index", id = "" }
                    // Parameter defaults
                  );
            }
    

    如果我请求网址: http://localhost/Home/Index ,然后由homeController.index()正确处理请求。

    但是,在我的生活中,我不知道URL/home/index是如何指向homecontroller的。据我所知,视图aspx没有引用homecontroller,homecontroller没有引用视图,路由表也没有明确提到homecontroller。这是怎么神奇地发生的?我肯定错过了一些明显的东西。

    然后

    3 回复  |  直到 15 年前
        1
  •  5
  •   Zhaph - Ben Duguid    15 年前

    随ASP.NET MVC一起提供的默认视图引擎可用于以下约定:

    您的文件夹结构如下:

    - Controllers\
    |-  HomeController.cs
    - Views\
    |- Home\
    |-- Index.aspx
    |- Shared\
    

    当一个请求进入并匹配在registerRoutes方法中定义的路由时(请参见 URL routing 有关更多信息),则调用匹配的控制器:

    routes.MapRoute(
      "Default", // Route name, allows you to call this route elsewhere
      "{controller}/{action}/{id}", // URL with parameters
      new { controller = "Home", action = "Index", id = "" } // Parameter defaults
      );
    

    在默认路由中,您还指定了默认控制器(不带“控制器”后缀)-路由引擎将自动添加 Controller 到控制器名称上-和一个默认操作。

    在控制器中,您调用简单方法:

    public ActionResult Index(){
      return View();
    }
    

    然后,默认视图引擎在“视图”文件夹(约定)中名为“主页”(与控制器相同)的文件夹中查找名为index(与操作相同)的ASPX文件。

    如果在其中找不到索引页,它还将在共享文件夹中查找索引页。

    ASP.NET MVC Nerd Dinner sample chapter

    ASP.NET MVC应用程序在解析视图模板时默认使用基于约定的目录命名结构。这允许开发人员在从控制器类中引用视图时避免完全限定位置路径。默认情况下,ASP.NET MVC将在 \Views\[ControllerName]\ 应用程序下的目录。

    这个 \Views\Shared 子目录提供了一种存储视图模板的方法,这些模板在应用程序中的多个控制器之间重复使用。当ASP.NET MVC尝试解析视图模板时,它将首先在 \Views\[Controller] 特定目录,如果它不能在那里找到视图模板,它将在 视图共享 目录。

    在命名单个视图模板时,建议的指导是让视图模板与导致其呈现的操作方法共享相同的名称。例如,上面的“index”操作方法使用“index”视图来呈现视图结果,“details”操作方法使用“details”视图来呈现其结果。这使得快速查看与每个操作关联的模板变得容易。

    当视图模板与在控制器上调用的操作方法同名时,开发人员不需要显式指定视图模板名称。我们可以将模型对象传递给 View() Helper方法(不指定视图名称)和ASP.NET MVC将自动推断我们要使用 \Views\[ControllerName]\[ActionName] 查看磁盘上的模板以呈现它。


    编辑添加:

    我已经设置的一些明确设置控制器的示例路由是:

    routes.MapRoute(
      "PhotoDetailsSlug",
      "Albums/{albumId}/{photoId}/{slug}",
      new {controller = "Albums", action = "PhotoDetails"},
      new {albumId = @"\d{1,4}", photoId = @"\d{1,8}"}
      );
    

    在这里,我明确地声明我正在使用相册控制器,并在上面使用photodetails操作,并将各种ID等传递给该操作。

        2
  •  6
  •   Darin Dimitrov    15 年前

    这是ASP.NET MVC中的约定。

    使用DefaultControllerFactory时,此约定被隐藏在内部密封类中 System.Web.Mvc.ControllerTypeCache (Microsoft编写内部密封类的典型方法)。在里面你会发现一个方法 EnsureInitialized 看起来是这样的:

    public void EnsureInitialized(IBuildManager buildManager)
    {
        if (this._cache == null)
        {
            lock (this._lockObj)
            {
                if (this._cache == null)
                {
                    this._cache = GetAllControllerTypes(buildManager).GroupBy<Type, string>(delegate (Type t) {
                        return t.Name.Substring(0, t.Name.Length - "Controller".Length);
                    }, StringComparer.OrdinalIgnoreCase).ToDictionary<IGrouping<string, Type>, string, ILookup<string, Type>>(delegate (IGrouping<string, Type> g) {
                        return g.Key;
                    }, delegate (IGrouping<string, Type> g) {
                        return g.ToLookup<Type, string>(t => t.Namespace ?? string.Empty, StringComparer.OrdinalIgnoreCase);
                    }, StringComparer.OrdinalIgnoreCase);
                }
            }
        }
    }
    

    注意分组的方式。因此,基本上,DefaultControllerFactory将在所有引用的程序集中查找实现控制器基类的类型,并从名称中除去“Controller”。

    如果您真的想详细分析ASP.NET MVC的管道,我建议您 excellent article .

        3
  •  2
  •   Yuriy Faktorovich    15 年前

    在操作索引中有一个语句 return View() . 当返回空白视图时,DefaultViewEngine会搜索多个默认文件夹以查找控制器方法的名称(特别是在findView方法中)。其中之一是views/home目录,因为home是控制器的名称。在那里它找到索引文件,并使用它来显示结果。