Маршрутизация

Определение маршрутов

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

В предыдущих главах при обращении к некоторому действию контроллера мы набирали в браузере адрес наподобие следующего http://localhost/Home/Index, где Home являлся именем контроллера без префикса Controller, а Index - именем действия этого контроллера. Если метод Index принимал какой-нибудь параметр, например, типа int: public ActionResult Index(int Id), то мы могли обратиться к этому методу и передать значение в его параметр с помощью следующей строки: http://localhost/Home/Index/5. Но мы не говорили еще о том, почему мы должны прописывать маршрут именно так, и как мы собственно можем управлять маршрутами.

Посмотрим, как определен маршрут. Если в MVC 3 для определения маршрута по умолчанию в файле Global.asax.cs создавался специальный метод RegisterRoutes, который определял маршрут по умолчанию и потом вызывался в методе Application_Start:

using System.Web.Routing;
using System.Data.Entity;

namespace MvcEmptyApp
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
			.............................
        }
		
		public static void RegisterRoutes(RouteCollection routes)
        {
            //Здесь определение маршрутов
			................................
        }
    }
}

То в MVC 4 все начальные настройки конфигурации для файла Global.asax.cs вынесены в классы, расположенные в папке App_Start. И затем эти классы вызываются в файле Global.asax.cs:

using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcEmptyApp
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}

Откроем файл RouteConfig.cs, расположенный в папке App_Start, в котором и находится определение маршрута по умолчанию:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcEmptyApp
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

Цель первой строки routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); отключить обработку запросов для некоторых файлов, например с расширением *.axd (WebResource.axd). Следующие два вызова - routes.MapHttpRoute и routes.MapRoute как раз и задают определение маршрута. Главное отличие состоит в том, что вызов routes.MapHttpRoute устанавливает сопоставления запроса некоторому маршруту для ресурса Web API, а routes.MapRoute устанавливает маршрут для обычного контроллера, которые мы использовали в предыдущих главах.

Поскольку тему Web API мы рассмотрим чуть позднее, поэтому пока поговорим об определении маршрута на примере обычного контроллера, к тому же в обоих определениях маршрутов много похожего.

Итак, метод MapRoute выполняет сопоставление маршрута запросу. Он имеет ряд перегруженных версий, которые помогают указать параметры сопоставления.

Здесь мы сначала задаем имя маршрута с помощью свойства name (в данном случае имя Default). С помощью параметра url мы задаем шаблон Url, с которым будет сопоставляться данный маршрут.

Шаблон URL состоит из нескольких сегментов, заключенных в фигурные скобки (сегмент - это часть запроса, находящаяся между слешами, но не включающая эти слеши). Каждый сегмент шаблона содержит параметр. Эти параметры называются параметрами URL.

При этом именовать параметры можно как угодно, используя любые алфавитно-цифровые символы. При получении запроса механизм маршрутизации парсит строку URL и помещает значения маршрута в словарь - в объект RouteValueDictionary, доступный через контекст приложения RequestContext. В качестве ключей используются имена параметров URL, а соответствующие сегменты URL в качестве значений. То есть, если строка запроса URL выглядит следующим образом: http://localhost/Home/Index/5, то у нас образуются следующие пары ключей и значений в словаре RouteValueDictionary:

Параметр

Значение

controller

Home

action

Index

id

5

Следующий параметр - defaults определяет значения по умолчанию для маршрута. И если вдруг в строке запроса мы не указали все параметры и попытались обратиться по адресу http://localhost/, то система маршрутизации вызовет метод Index контроллера Home, как указано в параметре defaults. Также, если мы не укажем метод контроллера, например, http://localhost/Home/, также будет вызван метод Index контроллера Home.

Поэтому если мы захотим, к примеру, чтобы у нас по умолчанию клиент обращался не к методу Index контроллера HomeController, а, например, к методу Show контроллера BookController, то мы можем соответственно изменить значения данного параметра:

defaults: new { controller = "Book", action = "Show", id = UrlParameter.Optional }

Последний параметр объявлен как необязательный id = UrlParameter.Optional, поэтому, если он не указан в строке запроса, он не будет учитываться и передаваться в словарь параметров RouteValueDictionary. Например, запрос http://localhost/Home/Create/3 вызовет метод Create контроллера Home, передав в этот метод в качестве параметра число 3. В то же время запрос http://localhost/Home/Create/ также вызовет метод Create контроллера Home, хотя последний параметр в нем не указан.

Таким образом, настройки по умолчанию позволяют нам не указывать в строке запроса полностью название контроллера и его метода. Но в случае если такие настройки не заданы, мы должны определять в строке запроса контроллер и его метод. Например, изменим установку маршрутов в файле RouteConfig.cs следующим образом:

public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}"
            );
        }
    }

При запуске из Visual Studio или при запуске в браузере по адресу http://mysyte.com/ мы получим информацию об ошибке. Ошибка будет состоять в том, что теперь нам полностью надо набирать в строке запроса адрес ресурса. Поэтому следующий адрес http://mysyte.com/Home/Index будет нормально работать (если у вас, конечно, определен контроллер Home с методом Index и соответствующим ему представлением).

И если мы теперь перейдем по адресу http://localhost/Home/, как мы это делали выше, то получим ошибку, так как у нас указан только одни сегмент. А в определении маршрута у нас указано два сегмента - {controller}/{action}. Если для параметров не определены значения по умолчанию, то строка запроса должна иметь такое же число сегментов, для которых не определены значения по умолчанию.

В то же время если запрос будет состоять из трех сегментов, например, http://localhost/Home/Index/1, то мы также получим ошибку, потому что число сегментов в запросе больше числа, определенного в шаблоне URL данного маршрута.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850