Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
AnchorTagHelper представляет тег-хелпер, который позволяет создавать ссылки. Он может принимать ряд специальных атрибутов:
asp-controller: указывает на контроллер, которому предназначен запрос
asp-action: указывает на действие контроллера
asp-area: указывает на действие область, в которой расположен контроллер или страница RazorPage (если они находятся в отдельной области)
asp-page: указывает на RazorPage, которая будет обрабатывать запрос
asp-page-handler: указывает на обработчик страницы RazorPage, которая будет применяться для обработки запроса
asp-host: указывает на домен сайта
asp-protocol: определяет протокол (http или https)
asp-route: указывает на название маршрута
asp-all-route-data: устанавливает набор значений для параметров
asp-route-[название параметра]: определяет значение для определенного параметра
asp-fragment: определяет ту часть хэш-ссылки, которая идет после символа решетки #. Например, "paragraph2" в ссылке "http://mysite.com/#paragraph2"
Мы можем создавать ссылки в ASP.NET Core различными способами. Например:
@Html.ActionLink("О сайте","About","Home") <a href='@Url.Action("About", "Home")'>О сайте</a>
В первом случае используется html-хелпер, во втором - стандартный элемент ссылки с хелпером Url.Content. Еще один способ предоставляют tag-хелпер AnchorTagHelper:
<a asp-controller="Home" asp-action="About">О сайте</a>
В данном случае используется не элемент html <a />
, а именно хелпер AnchorTagHelper. Его атрибут
asp-controller указывает на название контроллера, а asp-action
определяет действие, которому будет идти запрос. Если указан атрибут asp-action
, но не указан asp-controller
, то в качестве
контроллера используется тот контроллер, который связан с текущим представлением.
Если необходимо установить ссылку на действие контроллера, который находится в другой области, то применяется атрибут asp-area:
<a asp-controller="Home" asp-action="About" asp-route-area="Service">О сайте</a>
В данном случае предполагается, что контроллер Home находится в области Service.
Если, наоборот, в представлении, которое находится в какой-нибудь области, надо создать ссылку на действие контроллера, который не находится ни в какой области, то указывается пустой атрибут:
<a asp-controller="Home" asp-action="About" asp-route-area="">О сайте</a>
AnchorTagHelper по умолчанию создает локальную ссылку, если же нам надо создать ссылку на другой домен, то мы можем применить атрибут asp-host:
<a asp-controller="Home" asp-action="About" asp-host="localhost.com" asp-protocol="https">О сайте</a>
Кроме того, мы можем изменить стандартный протокол на https, использовав атрибут asp-protocol. Данный элемент в итоге создает следующую ссылку: https://localhost.com/Home/About
А что если у нас метод принимает какие-нибудь параметры, которые надо указать в ссылке:
public IActionResult GetPerson(int id){......}
В этом случае мы можем использовать атрибут asp-route-:
<a asp-controller="Home" asp-action="GetPerson" asp-route-id="5" >Item5</a>
Если метод принимает несколько параметров, например:
public IActionResult GetPerson(int id, string name, int age) { return Content($"id={id} name={name} age={age}"); }
то мы можем указать несколько атрибутов asp-route-
:
<a asp-controller="Home" asp-action="GetPerson" asp-route-id="5" asp-route-age="18" asp-route-name="tom" >Item5</a>
Чтобы не устанавливать все параметры по отдельности, можно применить атрибут asp-all-route-data:
<a asp-controller="Home" asp-action="GetPerson" asp-all-route-data='new Dictionary<string,string> { { "id", "5" }, {"name", "tom" }, { "age", "18" } }' >Item5</a>
asp-all-route-data
в качестве значения принимает словарь с параметрами и их значениями. В результате будет генерироваться
ссылка, аналогичная предыдущей.
При использовавании данного тег-хелпера может возникнуть вопрос, а какая именно ссылка будет сгенерирована? В реальности ответ на этот вопрос зависиот системы маршрутизации. Например, по умолчанию в проекте определен один маршрут (в методе Configure класса Startup):
endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
Возьмем предпоследний пример:
<a asp-controller="Home" asp-action="GetPerson" asp-route-id="5" asp-route-age="18" asp-route-name="tom" >Item5</a>
В итоге будет создаваться следующая ссылка: http://localhost:1234/Home/GetPerson/5?name=tom&age=18. Обратите внимание, что параметр id является частью шаблона маршрута, поэтому в сгенерированной ссылке он не входит строку запроса.
Если мы немного изменим определение маршрута, убрав сегмент параметра id:
endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}");
То параметр id будет трактоваться как часть строки запроса: http://localhost:60141/Home/GetPerson?id=5&name=tom&age=18
Но это только одна из частностей. Возьмем другой пример. Допустим, в классе Startup определено несколько маршрутов:
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "products", pattern: "Products/{action}/{id?}", defaults: new { controller = "Home" }); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
Первым здесь установлен маршрут "products", который будет сопоставлять запросы к контроллеру Home с маршрутом "Products/{action}/{id?}". В частности, запрос http://localhost:xxxxx/Products/Index будет обрабатываться методом Index контроллера Home.
И теперь следующий тег
<a asp-controller="Home" asp-action="Index">Жми здесь</a>
сгенерирует следующую ссылку
<a href="/Products/Index">Жми здесь</a>
И не смотря на то, что у нас также определен стандартный маршрут, который позволяет генерировать стандартные ссылки, включающие имя контроллера и имя его метода, но в данном случае для генерации ссылок будет применяться первый маршрут, который маршрут который совпадает с определением ссылки.
Но возьмем чуть более сложную систему маршрутов:
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "BookStore", defaults: new { controller = "Book", action = "Index" }); endpoints.MapControllerRoute( name: "default1", pattern: "Store/Sub{action}/{id?}", defaults: new { controller = "Home" }); endpoints.MapControllerRoute( name: "default2", pattern: "{controller=Home}/{action=Index}/{id?}"); });
Из определения маршрутов ясно, то запрос http://localhost:xxxxx/BookStore будет обрабатываться методом Index контроллера Book. А запрос http://localhost:xxxxx/Store/SubIndex/ будет обрабатываться контроллером Home и его методом Index.
Теперь пусть у нас в представлении создаются две ссылки:
<p> <a asp-controller="Home" asp-action="Index">Home</a> </p> <p> <a asp-controller="Book" asp-action="Index">Book</a> </p>
Первая ссылка соответствует второму маршруту, так как для определения ссылки используется контроллер Home. Поэтому в соответствии со вторым маршрутом будет сгенерирована следующая ссылка:
http://localhost:xxxxx/Store/SubIndex
Вторая же ссылка соответствует первому маршруту, который для обработки запроса применяет контроллер BookController. Поэтому второе выражение сгенерирует следующую ссылку:
http://localhost:xxxxx/BookStore
Поэтому если в приложении определено несколько маршрутов, то следует учитывать систему маршрутизации и проверять сгенерированные ссылки, иначе в результате можно получить совсем не то, что ожидалось.
С помощью параметра asp-route
можно сгенерировать ссылку на основании маршрута. Например, пусть у нас есть такой маршрут:
app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "book", pattern: "BookStore", defaults: new { controller = "Book", action = "Index" }); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
Возьмем первый маршрут по имени "book":
<a asp-route="book">Книги</a>
Такой тег создаст следующую ссылку:
<a href="/BookStore">Книги</a>