Маршрутизация и вложенные ресурсы

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

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

Нередко в различных соцсетях или других сервисах можно встретить ссылки такого типа https://twitter.com/SomeName/following или, например, https://plus.google.com/u/0/12344566556/posts. Эти две ссылки объединяет похожая схема маршрутизации - сначала идет общий путь, затем идентификатор пользователя (SomeName или 12344566556), и далее какое-то свойство, относящееся к пользователю - following (подписки в твиттере) или posts (все посты в Google+). Если мы посмотрим с точки зрения организации данных, то получится, что в некоторый класс пользователя хранит объекты постов или подписок. Таким образом, эти объекты оказываются как бы вложенными в объект пользователя. Посмотрим, как мы сможем создать систему маршрутов, чтобы обращаться к этим объектам как к вложенным и в asp.net mvc.

Допустим, у нас есть следующие классы, которые связаны по внешнему ключу и объекты которых храняться в базе данных:

public class Book
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int AuthorId { get; set; }
    public Author Author { get; set; }
}
public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Каждый объект Book хранит ссылку на связанного автора из таблицы авторов. Контекст данных мог бы выглядеть так:

public class BookContext : DbContext
{
    public DbSet<Book> Books { get; set; }
    public DbSet<Author> Authors { get; set; }
}

Теперь наша задача состоит в том, чтобы передать пользователю информацию о какой-либо книге и о ее авторе. Для этого создадим в контроллере HomeController два действия:

public ActionResult GetBook(int? id)
{
	if (id == null)
        return HttpNotFound();
    Book book = db.Books.Include(b => b.Author).FirstOrDefault(b=>b.Id == id);
    if (book == null)
        return HttpNotFound();
    return View(book);
}
public ActionResult GetAuthor(int? id)
{
	if (id == null)
        return HttpNotFound();
    Book book = db.Books.Include(b => b.Author).FirstOrDefault(b=>b.Id == id);
    if (book == null)
        return HttpNotFound();
    return View(book.Author);
}

Каждое действие получает нужную книгу по id и передает в строго типизированное представление объект книги или объект автора книги.

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

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

        routes.MapRoute(
            name: "author",
            url: "book/{id}/author",
            defaults: new { controller = "Home", action = "GetAuthor"}
        );

        routes.MapRoute(
            name: "book",
            url: "book/{id}",
            defaults: new { controller = "Home", action = "GetBook"}
        );

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

Итак, здесь мы добавляем два маршрута. Первый маршрут будет обрабатывать запрос типа book/1/author и сопоставлять его с методом GetAuthor (фактически будет представлять запрос home/getauthor/1). А второй маршрут будет обрабатывать запрос типа home/book/1 и сопоставлять его с методом GetBook.

И теперь мы можем запустить приложения и получить информацию о первой книге, набрав в браузере book/1/:

А если мы наберем book/1/author, то получим информацию об авторе этой книги:

И мы также могли использовать атрибуты маршрутизации, чтобы создать подобные маршруты:

[Route("book/{id}")]
public ActionResult GetBook(int? id)
{
    // остальной код
}
[Route("book/{id}/author")]
public ActionResult GetAuthor(int? id)
{
    // остальной код
}

А код в файле RouteConfig.cs выглядел бы следующим образом:

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

		routes.MapMvcAttributeRoutes();

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850