Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Нередко в различных соцсетях или других сервисах можно встретить ссылки такого типа 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 } ); } }