ASP.NET MVC 2 url/路由、视图与控制器有何关系?

发布于 2024-08-08 13:22:20 字数 985 浏览 7 评论 0原文

有人可以解释一下 MVC 2 中路由如何与控制器关联吗?目前,我在 /Controllers/HomeController.cs 中有一个控制器,并且有一个视图 /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
              );
        }

如果我请求 URL:http://localhost/Home/Index,那么该请求将被 HomeController.Index() 正确处理。

然而,在我的一生中,我无法弄清楚 url /Home/Index 是如何指向 HomeController 的。据我所知,视图 aspx 没有引用 HomeController,HomeController 没有引用视图,并且路由表没有明确提及 HomeController。这是如何神奇地发生的?我肯定错过了一些明显的东西。

然后

Could someone explain how routes are associated with controllers in MVC 2? Currently, I have a controller in /Controllers/HomeController.cs and a view /Home/Index.aspx.

My route registration method looks like this:

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

If I request the URL: http://localhost/Home/Index, then the request is correctly handled by HomeController.Index().

However, for the life of me, I can't figure out how the url /Home/Index gets pointed to HomeController. The view aspx doesn't, as far as I can tell, reference HomeController, HomeController doesn't reference the view, and the route table doesn't explicitly mention HomeController. How is this magically happening? Surely I'm missing something obvious.

then

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

黑寡妇 2024-08-15 13:22:20

这是 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 基类的类型,并从名称中删除“Controller”。

如果你真的想详细剖析 ASP.NET MVC 的管道,我会推荐你​​这个 优秀文章

This is the convention in ASP.NET MVC.

When using the DefaultControllerFactory this convention is buried inside the internal sealed class System.Web.Mvc.ControllerTypeCache (typical for Microsoft to write internal sealed classes). Inside you will find a method called EnsureInitialized which looks like this:

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

Pay attention how the grouping is made. So basically the DefaultControllerFactory will look inside all the referenced assemblies for types implementing the Controller base class and will strip the "Controller" from the name.

If you really want to dissect in details ASP.NET MVC's pipeline I would recommend you this excellent article.

故事未完 2024-08-15 13:22:20

ASP.NET MVC 附带的默认视图引擎遵循以下约定:

您有一个如下所示的文件夹结构:

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

当请求传入并匹配 RegisterRoutes 方法中定义的路由时(请参见 URL 路由了解更多),然后调用匹配的控制器:

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”后缀) - 路由引擎将自动将 Controller 添加到您的控制器名称 - 以及默认操作。

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

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

默认视图引擎然后在“Views”文件夹中名为“Home”(与控制器相同)的文件夹中查找名为 Index(与操作相同)的 aspx 文件(习俗)。

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

来自 ASP.NET MVC 书呆子晚餐示例章节

ASP.NET MVC 应用程序默认在解析视图模板时使用基于约定的目录命名结构。这使得开发人员可以避免在从 Controller 类中引用视图时必须完全限定位置路径。默认情况下,ASP.NET MVC 将在应用程序下的 \Views\[ControllerName]\ 目录中查找视图模板文件。

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

在命名单个视图模板时,建议的指导是让视图模板与导致其呈现的操作方法共享相同的名称。例如,上面我们的“Index”操作方法使用“Index”视图来呈现视图结果,而“Details”操作方法使用“Details”视图来呈现其结果。这样可以轻松快速地查看与每个操作关联的模板。

当视图模板与控制器上调用的操作方法同名时,开发人员不需要显式指定视图模板名称。我们可以直接将模型对象传递给 View() 辅助方法(不指定视图名称),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 等到那个动作。

The default views engine that comes with ASP.NET MVC works on the following conventions:

You have a folder structure like this:

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

When a request comes in, and matches a route defined in the RegisterRoutes method (see things like URL routing for more on that), then the matching controller is called:

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

In the default route, you are also specifying a default controller (without the "Controller" suffix) - the routing engine will automatically add Controller onto the controller name for you - and a default action.

In your controller, you call the simple method:

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

The default view engine then looks for an aspx file called Index (the same as the action) in a folder called "Home" (the same as the controller) in the "Views" folder (convention).

If it doesn't find one in there, it will also look for an index page in the Shared folder.

From the ASP.NET MVC Nerd Dinner sample chapter

ASP.NET MVC applications by default use a convention-based directory naming structure when resolving view templates. This allows developers to avoid having to fully-qualify a location path when referencing views from within a Controller class. By default ASP.NET MVC will look for the view template file within the \Views\[ControllerName]\ directory underneath the application.

The \Views\Shared subdirectory provides a way to store view templates that are re-used across multiple controllers within the application. When ASP.NET MVC attempts to resolve a view template, it will first check within the \Views\[Controller] specific directory, and if it can’t find the view template there it will look within the \Views\Shared directory.

When it comes to naming individual view templates, the recommended guidance is to have the view template share the same name as the action method that caused it to render. For example, above our "Index" action method is using the "Index" view to render the view result, and the "Details" action method is using the "Details" view to render its results. This makes it easy to quickly see which template is associated with each action.

Developers do not need to explicitly specify the view template name when the view template has the same name as the action method being invoked on the controller. We can instead just pass the model object to the View() helper method (without specifying the view name), and ASP.NET MVC will automatically infer that we want to use the \Views\[ControllerName]\[ActionName] view template on disk to render it.


Edit to add:

Some example routes I've set up, that explicitly set the controller are:

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

Here I'm explicitly stating that I'm using the Albums controller, and the PhotoDetails action on that, and passing in the various ids, etc to the that action.

国际总奸 2024-08-15 13:22:20

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

Inside the action Index there is a statement return View(). When a blank View is returned, the DefaultViewEngine searches several default folders for the name of the Controller method(specifically inside the FindView method). One of them is the Views/Home directory because Home is the name of the controller. There it finds the Index file, and uses it to display the result.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文