2009-10-20 1 views
4

Может ли кто-нибудь объяснить, как маршруты связаны с контроллерами в MVC 2? В настоящее время у меня есть контроллер в /Controllers/HomeController.cs и view /Home/Index.aspx.ASP.NET MVC 2 Как отображаются URL-адреса/маршруты, связанные с контроллерами?

Мой метод регистрации маршрут выглядит следующим образом:

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. Как это волшебно происходит? Конечно, я пропустил что-то очевидное.

затем

ответ

5

просмотров двигателя по умолчанию, который поставляется с 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(); 
} 

вид двигателя по умолчанию, то ищет файл ASPX под названием Index (такой же, как действие) в папку под названием «Home» (то же самое как контроллер) в папке «Просмотры» (соглашение).

Если он не находит его там, он также ищет индексную страницу в общей папке.

Из ASP.NET MVC Nerd Dinner sample chapter

приложений ASP.NET MVC по умолчанию использовать конвенционную структуру на основе имен каталогов при разрешении просмотра шаблонов. Это позволяет разработчикам избегать полной квалификации пути местоположения при обращении к представлениям из класса Controller. По умолчанию ASP.NET MVC будет искать файл шаблона представления в каталоге \Views\[ControllerName]\ под приложением.

Подкаталог \Views\Shared предоставляет способ хранения шаблонов заметок, которые повторно используются на нескольких контроллерах в приложении. Когда ASP.NET MVC пытается разрешить шаблон представления, он сначала проверяет в определенном каталоге \Views\[Controller], и если он не может найти шаблон представления, он будет искать в каталоге \Views\Shared.

Когда дело доходит до обозначения отдельных шаблонов заметок, рекомендуемое руководство состоит в том, чтобы шаблон представления имел то же имя, что и метод действия, который вызывал его визуализацию. Например, выше нашего метода «Индекс» использует представление «Индекс» для рендеринга результата представления, а метод действия «Подробности» использует представление «Подробности» для рендеринга его результатов. Это позволяет легко увидеть, какой шаблон связан с каждым действием.

Разработчикам не требуется явно указывать имя шаблона вида, если шаблон представления имеет то же имя, что и метод действия, вызываемый на контроллере. Вместо этого мы можем просто передать объект модели в вспомогательный метод 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 на нем, а также передачу различных идентификаторов и т. д. для этого действия.

+0

Большая часть этого имеет смысл. Однако объект по умолчанию, переданный в .MapRoute во втором фрагменте кода, ссылается на контроллер под названием «Главная».Мой класс контроллера называется «HomeController». Как я могу явно указать контроллер, используемый для определенного маршрута/url? –

+0

Вам нужно будет добавить явное правило для этих маршрутов и указать его в параметрах по умолчанию, для которых Controller (за исключением суффикса «Контроллер»). –

+0

Спасибо - я помету это как принято. Однако правильно ли я понимаю, что в приведенном выше примере «Альбомы» должны иметь соответствующий класс контроллера с именем «AlbumController»? –

2

Внутри индекса действия есть заявление return View(). Когда возвращается пустой вид, DefaultViewEngine выполняет поиск по нескольким папкам по умолчанию для имени метода Controller (особенно внутри метода FindView). Одним из них является каталог Views/Home, поскольку Home - это имя контроллера. Там он находит файл индекса и использует его для отображения результата.

+0

Это объясняет, как выглядит правильный вид, но как правильно выполнить метод контроллера? –

6

Это соглашение в 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.

+0

Это странно. Имя класса контроллера должно быть связано с URL-адресом ?! Что делать, если я хотел использовать один и тот же контроллер для URL-адреса, у которого не было имени контроллера? –

+1

Затем вы указываете его в своей таблице маршрутизации: 'routes.MapRoute (« MyRoute »,« someSpecialUrl/blabla », new {controller =« Home », action =« Index », id =« "}) ;, но вы все еще необходимо указать контроллер для использования. –

+0

Также, если установлен флаг StringComparer.OrdinalIgnoreCase, не означает ли это, что структура не сможет отличить HomeController и homecontroller? –