Roteamento para ações do controlador no ASP.NET CoreRouting to controller actions in ASP.NET Core

Por Ryan Nowak, Kirk Larkine Rick AndersonBy Ryan Nowak, Kirk Larkin, and Rick Anderson

Os controladores de ASP.NET Core usam o middleware de roteamento para corresponder as URLs de solicitações de entrada e mapeá-las para ações.ASP.NET Core controllers use the Routing middleware to match the URLs of incoming requests and map them to actions. Modelos de rotas:Routes templates:

  • São definidos em código ou atributos de inicialização.Are defined in startup code or attributes.
  • Descreva como os caminhos de URL são correspondidos às ações.Describe how URL paths are matched to actions.
  • São usados para gerar URLs para links.Are used to generate URLs for links. Os links gerados são normalmente retornados em respostas.The generated links are typically returned in responses.

As ações são roteadas por convenção ou roteadas por atributo.Actions are either conventionally-routed or attribute-routed. Colocar uma rota no controlador ou na ação a torna roteada por atributo.Placing a route on the controller or action makes it attribute-routed. Para obter mais informações, consulte Roteamento misto.See Mixed routing for more information.

Este documento:This document:

  • Explica as interações entre o MVC e o roteamento:Explains the interactions between MVC and routing:
    • Como os aplicativos MVC típicos fazem uso dos recursos de roteamento.How typical MVC apps make use of routing features.
    • Aborda ambos:Covers both:
    • Consulte Roteamento para obter detalhes avançados de roteamento.See Routing for advanced routing details.
  • Refere-se ao sistema de roteamento padrão adicionado no ASP.NET Core 3,0, chamado roteamento de ponto de extremidade.Refers to the default routing system added in ASP.NET Core 3.0, called endpoint routing. É possível usar controladores com a versão anterior do roteamento para fins de compatibilidade.It's possible to use controllers with the previous version of routing for compatibility purposes. Consulte o Guia de migração 2.2-3.0 para obter instruções.See the 2.2-3.0 migration guide for instructions. Consulte a versão 2,2 deste documento para obter material de referência sobre o sistema de roteamento herdado.Refer to the 2.2 version of this document for reference material on the legacy routing system.

Configurar a rota convencionalSet up conventional route

Startup.Configuregeralmente tem um código semelhante ao seguinte ao usar o Roteamento convencional:Startup.Configure typically has code similar to the following when using conventional routing:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});

Dentro da chamada para UseEndpoints , MapControllerRoute é usado para criar uma única rota.Inside the call to UseEndpoints, MapControllerRoute is used to create a single route. A rota única é chamada default rota.The single route is named default route. A maioria dos aplicativos com controladores e exibições usa um modelo de rota semelhante à default rota.Most apps with controllers and views use a route template similar to the default route. As APIs REST devem usar o Roteamento de atributos.REST APIs should use attribute routing.

O modelo de rota "{controller=Home}/{action=Index}/{id?}" :The route template "{controller=Home}/{action=Index}/{id?}":

  • Corresponde a um caminho de URL como/Products/Details/5Matches a URL path like /Products/Details/5

  • Extrai os valores de rota { controller = Products, action = Details, id = 5 } por tokening do caminho.Extracts the route values { controller = Products, action = Details, id = 5 } by tokenizing the path. A extração dos valores de rota resultará em uma correspondência se o aplicativo tiver um controlador chamado ProductsController e uma Details ação:The extraction of route values results in a match if the app has a controller named ProductsController and a Details action:

    public class ProductsController : Controller
    {
        public IActionResult Details(int id)
        {
            return ControllerContext.MyDisplayRouteInfo(id);
        }
    }
    

    MyDisplayRouteInfo é fornecido pelo pacote NuGet Rick. docs. Samples. RouteInfo e exibe informações de rota.MyDisplayRouteInfo is provided by the Rick.Docs.Samples.RouteInfo NuGet package and displays route information.

  • /Products/Details/5o modelo associa o valor de id = 5 para definir o id parâmetro como 5 ./Products/Details/5 model binds the value of id = 5 to set the id parameter to 5. Consulte Associação de modelo para obter mais detalhes.See Model Binding for more details.

  • {controller=Home}define Home como o padrão controller .{controller=Home} defines Home as the default controller.

  • {action=Index}define Index como o padrão action .{action=Index} defines Index as the default action.

  • O ? caractere em {id?} define id como opcional.The ? character in {id?} defines id as optional.

  • Parâmetros de rota opcionais e padrão não precisam estar presentes no caminho da URL para que haja uma correspondência.Default and optional route parameters don't need to be present in the URL path for a match. Consulte Referência de modelo de rota para obter uma descrição detalhada da sintaxe do modelo de rota.See Route Template Reference for a detailed description of route template syntax.

  • Corresponde ao caminho da URL / .Matches the URL path /.

  • Produz os valores de rota { controller = Home, action = Index } .Produces the route values { controller = Home, action = Index }.

Os valores para controller e action fazem uso dos valores padrão.The values for controller and action make use of the default values. idnão produz um valor, pois não há nenhum segmento correspondente no caminho da URL.id doesn't produce a value since there's no corresponding segment in the URL path. /corresponde somente se existir uma HomeController ação e Index :/ only matches if there exists a HomeController and Index action:

public class HomeController : Controller
{
  public IActionResult Index() { ... }
}

Usando a definição de controlador e o modelo de rota anteriores, a HomeController.Index ação é executada para os seguintes caminhos de URL:Using the preceding controller definition and route template, the HomeController.Index action is run for the following URL paths:

  • /Home/Index/17
  • /Home/Index
  • /Home
  • /

O caminho da URL / usa a ação e os controladores padrão do modelo de rota Home Index .The URL path / uses the route template default Home controllers and Index action. O caminho da URL /Home usa a ação padrão do modelo de rota Index .The URL path /Home uses the route template default Index action.

O método de conveniência MapDefaultControllerRoute:The convenience method MapDefaultControllerRoute:

endpoints.MapDefaultControllerRoute();

SubstitutoReplaces:

endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");

Importante

O roteamento é configurado usando o UseRouting e o UseEndpoints middleware.Routing is configured using the UseRouting and UseEndpoints middleware. Para usar controladores:To use controllers:

Roteamento convencionalConventional routing

O roteamento convencional é usado com controladores e exibições.Conventional routing is used with controllers and views. A rota default:The default route:

endpoints.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

é um exemplo de roteamento convencional.is an example of a conventional routing. Ele é chamado de Roteamento convencional porque estabelece uma Convenção para caminhos de URL:It's called conventional routing because it establishes a convention for URL paths:

  • O primeiro segmento de caminho, {controller=Home} , é mapeado para o nome do controlador.The first path segment, {controller=Home}, maps to the controller name.
  • O segundo segmento, {action=Index} , é mapeado para o nome da ação .The second segment, {action=Index}, maps to the action name.
  • O terceiro segmento {id?} é usado para um opcional id .The third segment, {id?} is used for an optional id. O ? no {id?} torna opcional.The ? in {id?} makes it optional. idé usado para mapear para uma entidade de modelo.id is used to map to a model entity.

Usando essa default rota, o caminho da URL:Using this default route, the URL path:

  • /Products/Listmapeia para a ProductsController.List ação./Products/List maps to the ProductsController.List action.
  • /Blog/Article/17mapeia para BlogController.Article e normalmente vincula o parâmetro a id 17./Blog/Article/17 maps to BlogController.Article and typically model binds the id parameter to 17.

Este mapeamento:This mapping:

  • É baseado somentenos nomes de controlador e de ação .Is based on the controller and action names only.
  • Não é baseado em namespaces, locais de arquivos de origem ou parâmetros de método.Isn't based on namespaces, source file locations, or method parameters.

O uso do roteamento convencional com a rota padrão permite a criação do aplicativo sem a necessidade de surgir um novo padrão de URL para cada ação.Using conventional routing with the default route allows creating the app without having to come up with a new URL pattern for each action. Para um aplicativo com ações de estilo CRUD , tendo consistência para as URLs entre controladores:For an app with CRUD style actions, having consistency for the URLs across controllers:

  • Ajuda a simplificar o código.Helps simplify the code.
  • Torna a interface do usuário mais previsível.Makes the UI more predictable.

Aviso

O id no código anterior é definido como opcional pelo modelo de rota.The id in the preceding code is defined as optional by the route template. As ações podem ser executadas sem a ID opcional fornecida como parte da URL.Actions can execute without the optional ID provided as part of the URL. Em geral, quando id é omitido da URL:Generally, whenid is omitted from the URL:

  • idé definido como 0 por associação de modelo.id is set to 0 by model binding.
  • Nenhuma entidade encontrada na correspondência de banco de dados id == 0 .No entity is found in the database matching id == 0.

O Roteamento de atributos fornece controle refinado para tornar a ID necessária para algumas ações e não para outras.Attribute routing provides fine-grained control to make the ID required for some actions and not for others. Por convenção, a documentação inclui parâmetros opcionais como id quando é provável que eles apareçam no uso correto.By convention, the documentation includes optional parameters like id when they're likely to appear in correct usage.

A maioria dos aplicativos deve escolher um esquema de roteamento básico e descritivo para que as URLs sejam legíveis e significativas.Most apps should choose a basic and descriptive routing scheme so that URLs are readable and meaningful. A rota convencional padrão {controller=Home}/{action=Index}/{id?}:The default conventional route {controller=Home}/{action=Index}/{id?}:

  • Dá suporte a um esquema de roteamento básico e descritivo.Supports a basic and descriptive routing scheme.
  • É um ponto de partida útil para aplicativos baseados em interface do usuário.Is a useful starting point for UI-based apps.
  • É o único modelo de rota necessário para muitos aplicativos da interface do usuário da Web.Is the only route template needed for many web UI apps. Para aplicativos de interface do usuário da Web maiores, outra rota usando áreas , se for sempre tudo o que for necessário.For larger web UI apps, another route using Areas if frequently all that's needed.

MapControllerRoutee MapAreaRoute :MapControllerRoute and MapAreaRoute :

  • Atribua automaticamente um valor de pedido aos seus pontos de extremidade com base na ordem em que são invocados.Automatically assign an order value to their endpoints based on the order they are invoked.

Roteamento de ponto de extremidade no ASP.NET Core 3,0 e posterior:Endpoint routing in ASP.NET Core 3.0 and later:

  • Não tem um conceito de rotas.Doesn't have a concept of routes.
  • Não fornece garantias de ordenação para a execução de extensibilidade, todos os pontos de extremidade são processados de uma só vez.Doesn't provide ordering guarantees for the execution of extensibility, all endpoints are processed at once.

Habilite o Log para ver como as implementações de roteamento internas, como Route, correspondem às solicitações.Enable Logging to see how the built-in routing implementations, such as Route, match requests.

O Roteamento de atributos é explicado mais adiante neste documento.Attribute routing is explained later in this document.

Várias rotas convencionaisMultiple conventional routes

Várias rotas convencionais podem ser adicionadas no UseEndpoints adicionando mais chamadas para MapControllerRoute e MapAreaControllerRoute .Multiple conventional routes can be added inside UseEndpoints by adding more calls to MapControllerRoute and MapAreaControllerRoute. Isso permite a definição de várias convenções ou a adição de rotas convencionais que são dedicadas a uma açãoespecífica, como:Doing so allows defining multiple conventions, or to adding conventional routes that are dedicated to a specific action, such as:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
});

A blog rota no código anterior é uma rota convencional dedicada.The blog route in the preceding code is a dedicated conventional route. Ele é chamado de rota convencional dedicada porque:It's called a dedicated conventional route because:

Porque controller e action não aparecem no modelo de rota "blog/{*article}" como parâmetros:Because controller and action don't appear in the route template "blog/{*article}" as parameters:

  • Eles só podem ter os valores padrão { controller = "Blog", action = "Article" } .They can only have the default values { controller = "Blog", action = "Article" }.
  • Essa rota sempre é mapeada para a ação BlogController.Article .This route always maps to the action BlogController.Article.

/Blog, /Blog/Article e /Blog/{any-string} são os únicos caminhos de URL que correspondem à rota do blog./Blog, /Blog/Article, and /Blog/{any-string} are the only URL paths that match the blog route.

O exemplo anterior:The preceding example:

  • bloga rota tem uma prioridade mais alta para correspondências que a default rota porque ela é adicionada primeiro.blog route has a higher priority for matches than the default route because it is added first.
  • É um exemplo de roteamento de estilo de separador, onde é comum ter um nome de artigo como parte da URL.Is and example of Slug style routing where it's typical to have an article name as part of the URL.

Aviso

No ASP.NET Core 3,0 e posterior, o roteamento não:In ASP.NET Core 3.0 and later, routing doesn't:

  • Defina um conceito chamado rota.Define a concept called a route. UseRoutingAdiciona correspondência de rota ao pipeline de middleware.UseRouting adds route matching to the middleware pipeline. O UseRouting middleware examina o conjunto de pontos de extremidade definidos no aplicativo e seleciona a melhor correspondência de ponto de extremidades com base na solicitação.The UseRouting middleware looks at the set of endpoints defined in the app, and selects the best endpoint match based on the request.
  • Forneça garantias sobre a ordem de execução de extensibilidade como IRouteConstraint ou IActionConstraint .Provide guarantees about the execution order of extensibility like IRouteConstraint or IActionConstraint.

Consulte Roteamento para obter material de referência sobre roteamento.See Routing for reference material on routing.

Ordem de roteamento convencionalConventional routing order

O roteamento convencional só corresponde a uma combinação de ação e controlador que são definidos pelo aplicativo.Conventional routing only matches a combination of action and controller that are defined by the app. Isso se destina a simplificar os casos em que as rotas convencionais se sobrepõem.This is intended to simplify cases where conventional routes overlap. Adicionar rotas usando MapControllerRoute , MapDefaultControllerRoute e MapAreaControllerRoute atribuir automaticamente um valor de pedido a seus pontos de extremidade com base na ordem em que são invocados.Adding routes using MapControllerRoute, MapDefaultControllerRoute, and MapAreaControllerRoute automatically assign an order value to their endpoints based on the order they are invoked. As correspondências de uma rota que aparece anteriormente têm uma prioridade mais alta.Matches from a route that appears earlier have a higher priority. O roteamento convencional é dependente da ordem.Conventional routing is order-dependent. Em geral, as rotas com áreas devem ser posicionadas antes, pois são mais específicas do que as rotas sem uma área.In general, routes with areas should be placed earlier as they're more specific than routes without an area. Rotas convencionais dedicadas com parâmetros de rota catch-all como {*article} podem tornar greedyuma rota muito grande, o que significa que ela corresponde às URLs que você pretende corresponder a outras rotas.Dedicated conventional routes with catch-all route parameters like {*article} can make a route too greedy, meaning that it matches URLs that you intended to be matched by other routes. Coloque as rotas de ávido mais tarde na tabela de rotas para evitar correspondências de caminhada.Put the greedy routes later in the route table to prevent greedy matches.

Aviso

Um parâmetro catch-all pode corresponder a rotas incorretamente devido a um bug no roteamento.A catch-all parameter may match routes incorrectly due to a bug in routing. Os aplicativos afetados por esse bug têm as seguintes características:Apps impacted by this bug have the following characteristics:

  • Uma rota catch-all, por exemplo,{**slug}"A catch-all route, for example, {**slug}"
  • A rota capturar tudo falha ao corresponder às solicitações que devem corresponder.The catch-all route fails to match requests it should match.
  • A remoção de outras rotas faz com que a rota capturar tudo comece a funcionar.Removing other routes makes catch-all route start working.

Veja bugs do GitHub 18677 e 16579 , por exemplo, casos que atingiram esse bug.See GitHub bugs 18677 and 16579 for example cases that hit this bug.

Uma correção de aceitação para esse bug está contida no SDK do .NET Core 3.1.301 e posterior.An opt-in fix for this bug is contained in .NET Core 3.1.301 SDK and later. O código a seguir define uma opção interna que corrige esse bug:The following code sets an internal switch that fixes this bug:

public static void Main(string[] args)
{
   AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior", 
                         true);
   CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.

Resolvendo ações ambíguasResolving ambiguous actions

Quando dois pontos de extremidade correspondem ao roteamento, o roteamento deve seguir um destes procedimentos:When two endpoints match through routing, routing must do one of the following:

  • Escolha o melhor candidato.Choose the best candidate.
  • Gera uma exceção.Throw an exception.

Por exemplo:For example:

    public class Products33Controller : Controller
    {
        public IActionResult Edit(int id)
        {
            return ControllerContext.MyDisplayRouteInfo(id);
        }

        [HttpPost]
        public IActionResult Edit(int id, Product product)
        {
            return ControllerContext.MyDisplayRouteInfo(id, product.name);
        }
    }
}

O controlador anterior define duas ações que correspondem a:The preceding controller defines two actions that match:

  • O caminho da URL/Products33/Edit/17The URL path /Products33/Edit/17
  • Rotear dados { controller = Products33, action = Edit, id = 17 } .Route data { controller = Products33, action = Edit, id = 17 }.

Esse é um padrão típico para controladores MVC:This is a typical pattern for MVC controllers:

  • Edit(int)exibe um formulário para editar um produto.Edit(int) displays a form to edit a product.
  • Edit(int, Product)processa o formulário Postado.Edit(int, Product) processes the posted form.

Para resolver a rota correta:To resolve the correct route:

  • Edit(int, Product)é selecionado quando a solicitação é um HTTP POST .Edit(int, Product) is selected when the request is an HTTP POST.
  • Edit(int)é selecionado quando o verbo http é qualquer outra coisa.Edit(int) is selected when the HTTP verb is anything else. Edit(int)é geralmente chamado por meio de GET .Edit(int) is generally called via GET.

O HttpPostAttribute , [HttpPost] , é fornecido ao roteamento para que ele possa escolher com base no método http da solicitação.The HttpPostAttribute, [HttpPost], is provided to routing so that it can choose based on the HTTP method of the request. O HttpPostAttribute faz Edit(int, Product) uma correspondência melhor do que Edit(int) .The HttpPostAttribute makes Edit(int, Product) a better match than Edit(int).

É importante entender a função de atributos como HttpPostAttribute .It's important to understand the role of attributes like HttpPostAttribute. Atributos semelhantes são definidos para outros verbos HTTP.Similar attributes are defined for other HTTP verbs. No Roteamento convencional, é comum que as ações usem o mesmo nome de ação quando fazem parte de um fluxo de trabalho de Mostrar formulário, enviar formulário.In conventional routing, it's common for actions to use the same action name when they're part of a show form, submit form workflow. Por exemplo, consulte examinar os dois métodos de ação de edição.For example, see Examine the two Edit action methods.

Se o roteamento não puder escolher um melhor candidato, um AmbiguousMatchException será gerado, listando os vários pontos de extremidade correspondentes.If routing can't choose a best candidate, an AmbiguousMatchException is thrown, listing the multiple matched endpoints.

Nomes de rota convencionaisConventional route names

As cadeias de caracteres "blog" e "default" nos exemplos a seguir são nomes de rota convencionais:The strings "blog" and "default" in the following examples are conventional route names:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
});

Os nomes de rota fornecem um nome lógico à rota.The route names give the route a logical name. A rota nomeada pode ser usada para a geração de URL.The named route can be used for URL generation. O uso de uma rota nomeada simplifica a criação de URL quando a ordenação de rotas pode tornar a geração de URL complicada.Using a named route simplifies URL creation when the ordering of routes could make URL generation complicated. Os nomes de rota devem ser de todo o aplicativo.Route names must be unique application wide.

Nomes de rota:Route names:

  • Não têm impacto sobre a correspondência de URL ou o tratamento de solicitações.Have no impact on URL matching or handling of requests.
  • São usados somente para a geração de URL.Are used only for URL generation.

O conceito de nome de rota é representado no roteamento como IEndpointNameMetadata.The route name concept is represented in routing as IEndpointNameMetadata. Os termos nome da rota e nome do ponto de extremidade:The terms route name and endpoint name:

  • São intercambiáveis.Are interchangeable.
  • Qual delas é usada na documentação e no código depende da API que está sendo descrita.Which one is used in documentation and code depends on the API being described.

Roteamento de atributos para APIs RESTAttribute routing for REST APIs

As APIs REST devem usar o roteamento de atributos para modelar a funcionalidade do aplicativo como um conjunto de recursos em que as operações são representadas por verbos HTTP.REST APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs.

O roteamento de atributo usa um conjunto de atributos para mapear ações diretamente para modelos de rota.Attribute routing uses a set of attributes to map actions directly to route templates. O código a seguir StartUp.Configure é típico para uma API REST e é usado no próximo exemplo:The following StartUp.Configure code is typical for a REST API and is used in the next sample:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

No código anterior, MapControllers é chamado dentro UseEndpoints para mapear controladores roteados de atributo.In the preceding code, MapControllers is called inside UseEndpoints to map attribute routed controllers.

No exemplo a seguir:In the following example:

  • O Configure método anterior é usado.The preceding Configure method is used.
  • HomeControllercorresponde a um conjunto de URLs semelhantes ao que a rota convencional padrão {controller=Home}/{action=Index}/{id?} corresponde.HomeController matches a set of URLs similar to what the default conventional route {controller=Home}/{action=Index}/{id?} matches.
public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

A HomeController.Index ação é executada para qualquer um dos caminhos de URL / , /Home , /Home/Index ou /Home/Index/3 .The HomeController.Index action is run for any of the URL paths /, /Home, /Home/Index, or /Home/Index/3.

Este exemplo realça uma importante diferença de programação entre roteamento de atributo e Roteamento convencional.This example highlights a key programming difference between attribute routing and conventional routing. O roteamento de atributos requer mais entrada para especificar uma rota.Attribute routing requires more input to specify a route. A rota padrão convencional lida com as rotas mais sucintamente.The conventional default route handles routes more succinctly. No entanto, o roteamento de atributos permite e exige um controle preciso de quais modelos de rota se aplicam a cada ação.However, attribute routing allows and requires precise control of which route templates apply to each action.

Com o roteamento de atributos, os nomes do controlador e da ação não desempenham nenhuma parte na qual a ação seja correspondida, a menos que a substituição do token seja usada.With attribute routing, the controller and action names play no part in which action is matched, unless token replacement is used. O exemplo a seguir corresponde às mesmas URLs do exemplo anterior:The following example matches the same URLs as the previous example:

public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

O código a seguir usa substituição de token para action e controller :The following code uses token replacement for action and controller:

public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("[controller]/[action]")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [Route("[controller]/[action]")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

O código a seguir se aplica [Route("[controller]/[action]")] ao controlador:The following code applies [Route("[controller]/[action]")] to the controller:

[Route("[controller]/[action]")]
public class HomeController : Controller
{
    [Route("~/")]
    [Route("/Home")]
    [Route("~/Home/Index")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

No código anterior, os Index modelos de método devem preceder / ou ~/ até os modelos de rota.In the preceding code, the Index method templates must prepend / or ~/ to the route templates. Modelos de rota aplicados a uma ação, que começam com / ou ~/, não são combinados com modelos de rota aplicados ao controlador.Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller.

Consulte precedência do modelo de rota para obter informações sobre a seleção do modelo de rota.See Route template precedence for information on route template selection.

Nomes reservados de roteamentoReserved routing names

As seguintes palavras-chave são nomes de parâmetro de rota reservados ao usar controladores ou Razor páginas:The following keywords are reserved route parameter names when using Controllers or Razor Pages:

  • action
  • area
  • controller
  • handler
  • page

O uso page de como um parâmetro de rota com roteamento de atributo é um erro comum.Using page as a route parameter with attribute routing is a common error. Fazer isso resulta em comportamento inconsistente e confuso com a geração de URL.Doing that results in inconsistent and confusing behavior with URL generation.

public class MyDemo2Controller : Controller
{
    [Route("/articles/{page}")]
    public IActionResult ListArticles(int page)
    {
        return ControllerContext.MyDisplayRouteInfo(page);
    }
}

Os nomes de parâmetro especiais são usados pela geração de URL para determinar se uma operação de geração de URL se refere a uma Razor página ou a um controlador.The special parameter names are used by the URL generation to determine if a URL generation operation refers to a Razor Page or to a Controller.

Modelos de verbo HTTPHTTP verb templates

ASP.NET Core tem os seguintes modelos de verbo HTTP:ASP.NET Core has the following HTTP verb templates:

Modelos de rotaRoute templates

ASP.NET Core tem os seguintes modelos de rota:ASP.NET Core has the following route templates:

Roteamento de atributos com atributos de verbo httpAttribute routing with Http verb attributes

Considere o seguinte controlador:Consider the following controller:

[Route("api/[controller]")]
[ApiController]
public class Test2Controller : ControllerBase
{
    [HttpGet]   // GET /api/test2
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       return ControllerContext.MyDisplayRouteInfo(id);
    }

    [HttpGet("int/{id:int}")] // GET /api/test2/int/3
    public IActionResult GetIntProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
    public IActionResult GetInt2Product(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

No código anterior:In the preceding code:

  • Cada ação contém o [HttpGet] atributo, que restringe a correspondência somente a solicitações HTTP Get.Each action contains the [HttpGet] attribute, which constrains matching to HTTP GET requests only.
  • A GetProduct ação inclui o "{id}" modelo, portanto, id é anexada ao "api/[controller]" modelo no controlador.The GetProduct action includes the "{id}" template, therefore id is appended to the "api/[controller]" template on the controller. O modelo de métodos é "api/[controller]/"{id}"" .The methods template is "api/[controller]/"{id}"". Portanto, essa ação só corresponde a solicitações GET de para o formulário /api/test2/xyz , /api/test2/123 ,, /api/test2/{any string} etc.Therefore this action only matches GET requests of for the form /api/test2/xyz,/api/test2/123,/api/test2/{any string}, etc.
    [HttpGet("{id}")]   // GET /api/test2/xyz
    public IActionResult GetProduct(string id)
    {
       return ControllerContext.MyDisplayRouteInfo(id);
    }
    
  • A GetIntProduct ação contém o "int/{id:int}") modelo.The GetIntProduct action contains the "int/{id:int}") template. A :int parte do modelo restringe os id valores de rota para cadeias de caracteres que podem ser convertidas em um número inteiro.The :int portion of the template constrains the id route values to strings that can be converted to an integer. Uma solicitação GET para /api/test2/int/abc :A GET request to /api/test2/int/abc:
    • Não corresponde a esta ação.Doesn't match this action.
    • Retorna um erro 404 não encontrado .Returns a 404 Not Found error.
      [HttpGet("int/{id:int}")] // GET /api/test2/int/3
      public IActionResult GetIntProduct(int id)
      {
          return ControllerContext.MyDisplayRouteInfo(id);
      }
      
  • A GetInt2Product ação contém {id} no modelo, mas não restringe id a valores que podem ser convertidos em um número inteiro.The GetInt2Product action contains {id} in the template, but doesn't constrain id to values that can be converted to an integer. Uma solicitação GET para /api/test2/int2/abc :A GET request to /api/test2/int2/abc:
    • Corresponde a essa rota.Matches this route.
    • A associação de modelo falha ao converter abc em um número inteiro.Model binding fails to convert abc to an integer. O id parâmetro do método é inteiro.The id parameter of the method is integer.
    • Retorna uma solicitação inadequada 400 porque a associação de modelo não pôde ser convertida abc em um número inteiro.Returns a 400 Bad Request because model binding failed to convertabc to an integer.
      [HttpGet("int2/{id}")]  // GET /api/test2/int2/3
      public IActionResult GetInt2Product(int id)
      {
          return ControllerContext.MyDisplayRouteInfo(id);
      }
      

O roteamento de atributos pode usar HttpMethodAttribute atributos como HttpPostAttribute , HttpPutAttribute e HttpDeleteAttribute .Attribute routing can use HttpMethodAttribute attributes such as HttpPostAttribute, HttpPutAttribute, and HttpDeleteAttribute. Todos os atributos de verbo http aceitam um modelo de rota.All of the HTTP verb attributes accept a route template. O exemplo a seguir mostra duas ações que correspondem ao mesmo modelo de rota:The following example shows two actions that match the same route template:

[ApiController]
public class MyProductsController : ControllerBase
{
    [HttpGet("/products3")]
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [HttpPost("/products3")]
    public IActionResult CreateProduct(MyProduct myProduct)
    {
        return ControllerContext.MyDisplayRouteInfo(myProduct.Name);
    }
}

Usando o caminho da URL /products3 :Using the URL path /products3:

  • A MyProductsController.ListProducts ação é executada quando o verbo http é GET .The MyProductsController.ListProducts action runs when the HTTP verb is GET.
  • A MyProductsController.CreateProduct ação é executada quando o verbo http é POST .The MyProductsController.CreateProduct action runs when the HTTP verb is POST.

Ao criar uma API REST, é raro que você precise usar [Route(...)] em um método de ação, pois a ação aceita todos os métodos http.When building a REST API, it's rare that you'll need to use [Route(...)] on an action method because the action accepts all HTTP methods. É melhor usar o atributo de verbo http mais específico para ser preciso em relação ao que sua API dá suporte.It's better to use the more specific HTTP verb attribute to be precise about what your API supports. Espera-se que clientes de APIs REST saibam quais caminhos e verbos HTTP são mapeados para operações lógicas específicas.Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.

As APIs REST devem usar o roteamento de atributos para modelar a funcionalidade do aplicativo como um conjunto de recursos em que as operações são representadas por verbos HTTP.REST APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs. Isso significa que muitas operações, por exemplo, GET e POST no mesmo recurso lógico usam a mesma URL.This means that many operations, for example, GET and POST on the same logical resource use the same URL. O roteamento de atributo fornece um nível de controle necessário para projetar cuidadosamente o layout de ponto de extremidade público de uma API.Attribute routing provides a level of control that's needed to carefully design an API's public endpoint layout.

Como uma rota de atributo se aplica a uma ação específica, é fácil fazer com que parâmetros sejam obrigatórios como parte da definição do modelo de rota.Since an attribute route applies to a specific action, it's easy to make parameters required as part of the route template definition. No exemplo a seguir, id é necessário como parte do caminho da URL:In the following example, id is required as part of the URL path:

[ApiController]
public class Products2ApiController : ControllerBase
{
    [HttpGet("/products2/{id}", Name = "Products_List")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

A Products2ApiController.GetProduct(int) ação:The Products2ApiController.GetProduct(int) action:

  • É executado com caminho de URL como/products2/3Is run with URL path like /products2/3
  • Não é executado com o caminho da URL /products2 .Isn't run with the URL path /products2.

O atributo [consume] permite que uma ação limite os tipos de conteúdo de solicitação com suporte.The [Consumes] attribute allows an action to limit the supported request content types. Para obter mais informações, consulte definir tipos de conteúdo de solicitação com suporte com o atributo consumes.For more information, see Define supported request content types with the Consumes attribute.

Consulte Roteamento para obter uma descrição completa de modelos de rota e as opções relacionadas.See Routing for a full description of route templates and related options.

Para obter mais informações sobre o [ApiController] , consulte o atributo ApiController.For more information on [ApiController], see ApiController attribute.

Nome da rotaRoute name

O código a seguir define um nome da rota como Products_List:The following code defines a route name of Products_List:

[ApiController]
public class Products2ApiController : ControllerBase
{
    [HttpGet("/products2/{id}", Name = "Products_List")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

Nomes de rota podem ser usados para gerar uma URL com base em uma rota específica.Route names can be used to generate a URL based on a specific route. Nomes de rota:Route names:

  • Não têm impacto sobre o comportamento de correspondência de URL do roteamento.Have no impact on the URL matching behavior of routing.
  • São usados somente para a geração de URL.Are only used for URL generation.

Nomes de rotas devem ser exclusivos no nível do aplicativo.Route names must be unique application-wide.

Compare o código anterior com a rota padrão convencional, que define o id parâmetro como opcional ( {id?} ).Contrast the preceding code with the conventional default route, which defines the id parameter as optional ({id?}). A capacidade de especificar precisamente as APIs tem vantagens, como permitir /products e /products/5 ser expedida para ações diferentes.The ability to precisely specify APIs has advantages, such as allowing /products and /products/5 to be dispatched to different actions.

Combinando rotas de atributoCombining attribute routes

Para tornar o roteamento de atributo menos repetitivo, os atributos de rota no controlador são combinados com atributos de rota nas ações individuais.To make attribute routing less repetitive, route attributes on the controller are combined with route attributes on the individual actions. Modelos de rota definidos no controlador precedem modelos de rota nas ações. Any route templates defined on the controller are prepended to route templates on the actions. Colocar um atributo de rota no controlador foz com que todas as ações no controlador usem o roteamento de atributo.Placing a route attribute on the controller makes all actions in the controller use attribute routing.

[ApiController]
[Route("products")]
public class ProductsApiController : ControllerBase
{
    [HttpGet]
    public IActionResult ListProducts()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [HttpGet("{id}")]
    public IActionResult GetProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

No exemplo anterior:In the preceding example:

  • O caminho da URL /products pode corresponderProductsApi.ListProductsThe URL path /products can match ProductsApi.ListProducts
  • O caminho da URL /products/5 pode corresponder ProductsApi.GetProduct(int) .The URL path /products/5 can match ProductsApi.GetProduct(int).

Ambas as ações correspondem apenas a HTTP GET porque elas são marcadas com o [HttpGet] atributo.Both of these actions only match HTTP GET because they're marked with the [HttpGet] attribute.

Modelos de rota aplicados a uma ação, que começam com / ou ~/, não são combinados com modelos de rota aplicados ao controlador.Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller. O exemplo a seguir corresponde a um conjunto de caminhos de URL semelhante à rota padrão.The following example matches a set of URL paths similar to the default route.

[Route("Home")]
public class HomeController : Controller
{
    [Route("")]
    [Route("Index")]
    [Route("/")]
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [Route("About")]
    public IActionResult About()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

A tabela a seguir explica os [Route] atributos no código anterior:The following table explains the [Route] attributes in the preceding code:

AtributoAttribute Combina com[Route("Home")]Combines with [Route("Home")] Define o modelo de rotaDefines route template
[Route("")] SimYes "Home"
[Route("Index")] SimYes "Home/Index"
[Route("/")] NãoNo ""
[Route("About")] YesYes "Home/About"

Ordem de rota de atributoAttribute route order

O roteamento cria uma árvore e corresponde a todos os pontos de extremidade simultaneamente:Routing builds a tree and matches all endpoints simultaneously:

  • As entradas de rota se comportam como se colocadas em uma ordenação ideal.The route entries behave as if placed in an ideal ordering.
  • As rotas mais específicas têm a chance de serem executadas antes das rotas mais gerais.The most specific routes have a chance to execute before the more general routes.

Por exemplo, uma rota de atributo como blog/search/{topic} é mais específica do que uma rota de atributo como blog/{*article} .For example, an attribute route like blog/search/{topic} is more specific than an attribute route like blog/{*article}. A blog/search/{topic} rota tem prioridade mais alta, por padrão, porque é mais específica.The blog/search/{topic} route has higher priority, by default, because it's more specific. Usando o Roteamento convencional, o desenvolvedor é responsável por colocar rotas na ordem desejada.Using conventional routing, the developer is responsible for placing routes in the desired order.

As rotas de atributo podem configurar um pedido usando a Order propriedade.Attribute routes can configure an order using the Order property. Todos os atributos de rota fornecidos pelo Framework incluem Order .All of the framework provided route attributes include Order . As rotas são processadas segundo uma classificação crescente da propriedade Order.Routes are processed according to an ascending sort of the Order property. A ordem padrão é 0.The default order is 0. Definir uma rota usando Order = -1 execuções antes das rotas que não definem um pedido.Setting a route using Order = -1 runs before routes that don't set an order. Definir uma rota usando Order = 1 execuções após a ordenação de rota padrão.Setting a route using Order = 1 runs after default route ordering.

Evite , dependendo de Order .Avoid depending on Order. Se o espaço de URL de um aplicativo exigir valores de ordem explícitos para rotear corretamente, isso provavelmente será confuso para os clientes também.If an app's URL-space requires explicit order values to route correctly, then it's likely confusing to clients as well. Em geral, o roteamento de atributos seleciona a rota correta com correspondência de URL.In general, attribute routing selects the correct route with URL matching. Se a ordem padrão usada para a geração de URL não estiver funcionando, o uso de um nome de rota como uma substituição normalmente será mais simples do que aplicar a Order propriedade.If the default order used for URL generation isn't working, using a route name as an override is usually simpler than applying the Order property.

Considere os dois controladores a seguir que definem a rota correspondente /home :Consider the following two controllers which both define the route matching /home:

public class HomeController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult Index(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult About(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}
public class MyDemoController : Controller
{
    [Route("")]
    [Route("Home")]
    [Route("Home/Index")]
    [Route("Home/Index/{id?}")]
    public IActionResult MyIndex(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    [Route("Home/About")]
    [Route("Home/About/{id?}")]
    public IActionResult MyAbout(int? id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

A solicitação /home com o código anterior gera uma exceção semelhante à seguinte:Requesting /home with the preceding code throws an exception similar to the following:

AmbiguousMatchException: The request matched multiple endpoints. Matches:

 WebMvcRouting.Controllers.HomeController.Index
 WebMvcRouting.Controllers.MyDemoController.MyIndex

Adicionar Order a um dos atributos de rota resolve a ambiguidade:Adding Order to one of the route attributes resolves the ambiguity:

[Route("")]
[Route("Home", Order = 2)]
[Route("Home/MyIndex")]
public IActionResult MyIndex()
{
    return ControllerContext.MyDisplayRouteInfo();
}

Com o código anterior, /home executa o HomeController.Index ponto de extremidade.With the preceding code, /home runs the HomeController.Index endpoint. Para obter a MyDemoController.MyIndex solicitação, /home/MyIndex .To get to the MyDemoController.MyIndex, request /home/MyIndex. Observação:Note:

  • O código anterior é um exemplo de design de roteamento insatisfatório.The preceding code is an example or poor routing design. Ele foi usado para ilustrar a Order propriedade.It was used to illustrate the Order property.
  • A Order Propriedade resolve apenas a ambiguidade, esse modelo não pode ser correspondido.The Order property only resolves the ambiguity, that template cannot be matched. Seria melhor remover o [Route("Home")] modelo.It would be better to remove the [Route("Home")] template.

Consulte as Razor páginas rota e convenções de aplicativo: ordem de rota para obter informações sobre a ordem de rota com Razor páginas.See Razor Pages route and app conventions: Route order for information on route order with Razor Pages.

Em alguns casos, um erro HTTP 500 é retornado com rotas ambíguas.In some cases, an HTTP 500 error is returned with ambiguous routes. Use o registro em log para ver quais pontos de extremidade causaram o AmbiguousMatchException .Use logging to see which endpoints caused the AmbiguousMatchException.

Substituição de token em modelos de rota [controlador], [ação], [área]Token replacement in route templates [controller], [action], [area]

Para sua conveniência, as rotas de atributo dão suporte à substituição de token para parâmetros de rota reservados ao colocar um token em um dos seguintes:For convenience, attribute routes support token replacement for reserved route parameters by enclosing a token in one of the following:

  • Colchetes:[]Square brackets: []
  • Chaves:{}Curly braces: {}

Os tokens [action] , [area] , e [controller] são substituídos pelos valores do nome da ação, do nome da área e do nome do controlador da ação em que a rota é definida:The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where the route is defined:

[Route("[controller]/[action]")]
public class Products0Controller : Controller
{
    [HttpGet]
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }


    [HttpGet("{id}")]
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

No código anterior:In the preceding code:

[HttpGet]
public IActionResult List()
{
    return ControllerContext.MyDisplayRouteInfo();
}
  • Acordo/Products0/ListMatches /Products0/List
[HttpGet("{id}")]
public IActionResult Edit(int id)
{
    return ControllerContext.MyDisplayRouteInfo(id);
}
  • Acordo/Products0/Edit/{id}Matches /Products0/Edit/{id}

A substituição de token ocorre como a última etapa da criação das rotas de atributo.Token replacement occurs as the last step of building the attribute routes. O exemplo anterior se comporta da mesma forma que o código a seguir:The preceding example behaves the same as the following code:

public class Products20Controller : Controller
{
    [HttpGet("[controller]/[action]")]  // Matches '/Products20/List'
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [HttpGet("[controller]/[action]/{id}")]   // Matches '/Products20/Edit/{id}'
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

Se você estiver lendo isso em um idioma diferente do inglês, informe-nos sobre esse problema de discussão do GitHub se quiser ver os comentários de código em seu idioma nativo.If you are reading this in a language other than English, let us know in this GitHub discussion issue if you'd like to see the code comments in your native language.

Rotas de atributo também podem ser combinadas com herança.Attribute routes can also be combined with inheritance. Isso é poderoso combinado com a substituição de token.This is powerful combined with token replacement. A substituição de token também se aplica a nomes de rota definidos por rotas de atributo.Token replacement also applies to route names defined by attribute routes. [Route("[controller]/[action]", Name="[controller]_[action]")]gera um nome de rota exclusivo para cada ação:[Route("[controller]/[action]", Name="[controller]_[action]")]generates a unique route name for each action:

[ApiController]
[Route("api/[controller]/[action]", Name = "[controller]_[action]")]
public abstract class MyBase2Controller : ControllerBase
{
}

public class Products11Controller : MyBase2Controller
{
    [HttpGet]                      // /api/products11/
    public IActionResult List()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [HttpGet("{id}")]             //    /api/products11/edit/3
    public IActionResult Edit(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

A substituição de token também se aplica a nomes de rota definidos por rotas de atributo.Token replacement also applies to route names defined by attribute routes. [Route("[controller]/[action]", Name="[controller]_[action]")] gera um nome de rota exclusivo para cada ação.generates a unique route name for each action.

Para corresponder ao delimitador de substituição de token literal [ ou ], faça seu escape repetindo o caractere ([[ ou ]]).To match the literal token replacement delimiter [ or ], escape it by repeating the character ([[ or ]]).

Usar um transformador de parâmetro para personalizar a substituição de tokenUse a parameter transformer to customize token replacement

A substituição do token pode ser personalizada usando um transformador de parâmetro.Token replacement can be customized using a parameter transformer. Um transformador de parâmetro implementa IOutboundParameterTransformer e transforma o valor dos parâmetros.A parameter transformer implements IOutboundParameterTransformer and transforms the value of parameters. Por exemplo, um SlugifyParameterTransformer transformador de parâmetro personalizado altera o SubscriptionManagement valor de rota para subscription-management :For example, a custom SlugifyParameterTransformer parameter transformer changes the SubscriptionManagement route value to subscription-management:

public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object value)
    {
        if (value == null) { return null; }

        return Regex.Replace(value.ToString(),
                             "([a-z])([A-Z])",
                             "$1-$2",
                             RegexOptions.CultureInvariant,
                             TimeSpan.FromMilliseconds(100)).ToLowerInvariant();
    }
}

O RouteTokenTransformerConvention é uma convenção de modelo de aplicativo que:The RouteTokenTransformerConvention is an application model convention that:

  • Aplica um transformador de parâmetro a todas as rotas de atributo em um aplicativo.Applies a parameter transformer to all attribute routes in an application.
  • Personaliza os valores de token de rota de atributo conforme eles são substituídos.Customizes the attribute route token values as they are replaced.
public class SubscriptionManagementController : Controller
{
    [HttpGet("[controller]/[action]")]
    public IActionResult ListAll()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

O ListAll método anterior corresponde a /subscription-management/list-all .The preceding ListAll method matches /subscription-management/list-all.

O RouteTokenTransformerConvention está registrado como uma opção em ConfigureServices.The RouteTokenTransformerConvention is registered as an option in ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Conventions.Add(new RouteTokenTransformerConvention(
                                     new SlugifyParameterTransformer()));
    });
}

Consulte MDN Web docs no separador para obter a definição do separador.See MDN web docs on Slug for the definition of Slug.

Aviso

Ao usar System.Text.RegularExpressions o para processar a entrada não confiável, passe um tempo limite.When using System.Text.RegularExpressions to process untrusted input, pass a timeout. Um usuário mal-intencionado pode fornecer entrada para RegularExpressions causar um ataque de negação de serviço.A malicious user can provide input to RegularExpressions causing a Denial-of-Service attack. ASP.NET Core APIs do Framework que RegularExpressions usam passar um tempo limite.ASP.NET Core framework APIs that use RegularExpressions pass a timeout.

Várias rotas de atributosMultiple attribute routes

O roteamento de atributo dá suporte à definição de várias rotas que atingem a mesma ação.Attribute routing supports defining multiple routes that reach the same action. O uso mais comum desse recurso é para simular o comportamento da rota convencional padrão, conforme mostrado no exemplo a seguir:The most common usage of this is to mimic the behavior of the default conventional route as shown in the following example:

[Route("[controller]")]
public class Products13Controller : Controller
{
    [Route("")]     // Matches 'Products13'
    [Route("Index")] // Matches 'Products13/Index'
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

Colocar vários atributos de rota no controlador significa que cada um combina com cada um dos atributos de rota nos métodos de ação:Putting multiple route attributes on the controller means that each one combines with each of the route attributes on the action methods:

[Route("Store")]
[Route("[controller]")]
public class Products6Controller : Controller
{
    [HttpPost("Buy")]       // Matches 'Products6/Buy' and 'Store/Buy'
    [HttpPost("Checkout")]  // Matches 'Products6/Checkout' and 'Store/Checkout'
    public IActionResult Buy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

Todas as restrições de rota de verbo http implementam IActionConstraint .All the HTTP verb route constraints implement IActionConstraint.

Quando vários atributos de rota implementados IActionConstraint são colocados em uma ação:When multiple route attributes that implement IActionConstraint are placed on an action:

  • Cada restrição de ação combina com o modelo de rota aplicado ao controlador.Each action constraint combines with the route template applied to the controller.
[Route("api/[controller]")]
public class Products7Controller : ControllerBase
{
    [HttpPut("Buy")]        // Matches PUT 'api/Products7/Buy'
    [HttpPost("Checkout")]  // Matches POST 'api/Products7/Checkout'
    public IActionResult Buy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

O uso de várias rotas em ações pode parecer útil e eficiente, é melhor manter o espaço de URL básico e bem definido do aplicativo.Using multiple routes on actions might seem useful and powerful, it's better to keep your app's URL space basic and well defined. Use várias rotas em ações somente quando necessário, por exemplo, para dar suporte a clientes existentes.Use multiple routes on actions only where needed, for example, to support existing clients.

Especificando parâmetros opcionais, valores padrão e restrições da rota de atributoSpecifying attribute route optional parameters, default values, and constraints

Rotas de atributo dão suporte à mesma sintaxe embutida que as rotas convencionais para especificar parâmetros opcionais, valores padrão e restrições.Attribute routes support the same inline syntax as conventional routes to specify optional parameters, default values, and constraints.

public class Products14Controller : Controller
{
    [HttpPost("product14/{id:int}")]
    public IActionResult ShowProduct(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

No código anterior, o [HttpPost("product/{id:int}")] aplica uma restrição de rota.In the preceding code, [HttpPost("product/{id:int}")] applies a route constraint. A ProductsController.ShowProduct ação é correspondida somente por caminhos de URL como /product/3 .The ProductsController.ShowProduct action is matched only by URL paths like /product/3. A parte do modelo de rota {id:int} restringe esse segmento a apenas inteiros.The route template portion {id:int} constrains that segment to only integers.

Consulte Referência de modelo de rota para obter uma descrição detalhada da sintaxe do modelo de rota.See Route Template Reference for a detailed description of route template syntax.

Atributos de rota personalizados usando IRouteTemplateProviderCustom route attributes using IRouteTemplateProvider

Todos os atributos de rota implementam IRouteTemplateProvider .All of the route attributes implement IRouteTemplateProvider. O tempo de execução de ASP.NET Core:The ASP.NET Core runtime:

  • Procura atributos em classes de controlador e métodos de ação quando o aplicativo é iniciado.Looks for attributes on controller classes and action methods when the app starts.
  • Usa os atributos que implementam IRouteTemplateProvider para compilar o conjunto inicial de rotas.Uses the attributes that implement IRouteTemplateProvider to build the initial set of routes.

Implemente IRouteTemplateProvider para definir atributos de rota personalizados.Implement IRouteTemplateProvider to define custom route attributes. Cada IRouteTemplateProvider permite definir uma única rota com um nome, uma ordem e um modelo de rota personalizado:Each IRouteTemplateProvider allows you to define a single route with a custom route template, order, and name:

public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider
{
    public string Template => "api/[controller]";
    public int? Order => 2;
    public string Name { get; set; }
}

[MyApiController]
[ApiController]
public class MyTestApiController : ControllerBase
{
    // GET /api/MyTestApi
    [HttpGet]
    public IActionResult Get()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

O Get método anterior retorna Order = 2, Template = api/MyTestApi .The preceding Get method returns Order = 2, Template = api/MyTestApi.

Usar o modelo de aplicativo para personalizar as rotas de atributoUse application model to customize attribute routes

O modelo de aplicativo:The application model:

  • É um modelo de objeto criado na inicialização.Is an object model created at startup.
  • Contém todos os metadados usados pelo ASP.NET Core para rotear e executar as ações em um aplicativo.Contains all of the metadata used by ASP.NET Core to route and execute the actions in an app.

O modelo de aplicativo inclui todos os dados coletados dos atributos de rota.The application model includes all of the data gathered from route attributes. Os dados dos atributos de rota são fornecidos pela IRouteTemplateProvider implementação.The data from route attributes is provided by the IRouteTemplateProvider implementation. RegrasConventions:

  • Pode ser escrito para modificar o modelo de aplicativo para personalizar a forma como o roteamento se comporta.Can be written to modify the application model to customize how routing behaves.
  • São lidos na inicialização do aplicativo.Are read at app startup.

Esta seção mostra um exemplo básico de personalização de roteamento usando o modelo de aplicativo.This section shows a basic example of customizing routing using application model. O código a seguir torna as rotas aproximadamente alinhadas com a estrutura de pastas do projeto.The following code makes routes roughly line up with the folder structure of the project.

public class NamespaceRoutingConvention : Attribute, IControllerModelConvention
{
    private readonly string _baseNamespace;

    public NamespaceRoutingConvention(string baseNamespace)
    {
        _baseNamespace = baseNamespace;
    }

    public void Apply(ControllerModel controller)
    {
        var hasRouteAttributes = controller.Selectors.Any(selector =>
                                                selector.AttributeRouteModel != null);
        if (hasRouteAttributes)
        {
            return;
        }

        var namespc = controller.ControllerType.Namespace;
        if (namespc == null)
            return;
        var template = new StringBuilder();
        template.Append(namespc, _baseNamespace.Length + 1,
                        namespc.Length - _baseNamespace.Length - 1);
        template.Replace('.', '/');
        template.Append("/[controller]/[action]/{id?}");

        foreach (var selector in controller.Selectors)
        {
            selector.AttributeRouteModel = new AttributeRouteModel()
            {
                Template = template.ToString()
            };
        }
    }
}

O código a seguir impede que a namespace Convenção seja aplicada a controladores que são roteados por atributo:The following code prevents the namespace convention from being applied to controllers that are attribute routed:

public void Apply(ControllerModel controller)
{
    var hasRouteAttributes = controller.Selectors.Any(selector =>
                                            selector.AttributeRouteModel != null);
    if (hasRouteAttributes)
    {
        return;
    }

Por exemplo, o controlador a seguir não usa NamespaceRoutingConvention :For example, the following controller doesn't use NamespaceRoutingConvention:

[Route("[controller]/[action]/{id?}")]
public class ManagersController : Controller
{
    // /managers/index
    public IActionResult Index()
    {
        var template = ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
        return Content($"Index- template:{template}");
    }

    public IActionResult List(int? id)
    {
        var path = Request.Path.Value;
        return Content($"List- Path:{path}");
    }
}

O método NamespaceRoutingConvention.Apply:The NamespaceRoutingConvention.Apply method:

  • Não fará nada se o controlador for um atributo roteado.Does nothing if the controller is attribute routed.
  • Define o modelo de controladores com base no namespace , com a base namespace removida.Sets the controllers template based on the namespace, with the base namespace removed.

O NamespaceRoutingConvention pode ser aplicado em Startup.ConfigureServices :The NamespaceRoutingConvention can be applied in Startup.ConfigureServices:

namespace My.Application
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews(options =>
            {
                options.Conventions.Add(
                    new NamespaceRoutingConvention(typeof(Startup).Namespace));
            });
        }
        // Remaining code ommitted for brevity.

Por exemplo, considere o seguinte controlador:For example, consider the following controller:

using Microsoft.AspNetCore.Mvc;

namespace My.Application.Admin.Controllers
{
    public class UsersController : Controller
    {
        // GET /admin/controllers/users/index
        public IActionResult Index()
        {
            var fullname = typeof(UsersController).FullName;
            var template = 
                ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
            var path = Request.Path.Value;

            return Content($"Path: {path} fullname: {fullname}  template:{template}");
        }

        public IActionResult List(int? id)
        {
            var path = Request.Path.Value;
            return Content($"Path: {path} ID:{id}");
        }
    }
}

No código anterior:In the preceding code:

  • A base namespace é My.Application .The base namespace is My.Application.
  • O nome completo do controlador anterior é My.Application.Admin.Controllers.UsersController .The full name of the preceding controller is My.Application.Admin.Controllers.UsersController.
  • O NamespaceRoutingConvention define o modelo de controladores como Admin/Controllers/Users/[action]/{id? .The NamespaceRoutingConvention sets the controllers template to Admin/Controllers/Users/[action]/{id?.

O NamespaceRoutingConvention também pode ser aplicado como um atributo em um controlador:The NamespaceRoutingConvention can also be applied as an attribute on a controller:

[NamespaceRoutingConvention("My.Application")]
public class TestController : Controller
{
    // /admin/controllers/test/index
    public IActionResult Index()
    {
        var template = ControllerContext.ActionDescriptor.AttributeRouteInfo?.Template;
        var actionname = ControllerContext.ActionDescriptor.ActionName;
        return Content($"Action- {actionname} template:{template}");
    }

    public IActionResult List(int? id)
    {
        var path = Request.Path.Value;
        return Content($"List- Path:{path}");
    }
}

Roteamento misto: roteamento de atributo versus roteamento convencionalMixed routing: Attribute routing vs conventional routing

ASP.NET Core aplicativos podem misturar o uso de roteamento convencional e roteamento de atributos.ASP.NET Core apps can mix the use of conventional routing and attribute routing. É comum usar rotas convencionais para controladores que servem páginas HTML para navegadores e usar o roteamento de atributo para controladores que servem APIs REST.It's typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs.

As ações são roteadas convencionalmente ou segundo os atributos.Actions are either conventionally routed or attribute routed. Colocar uma rota no controlador ou na ação faz com que ela seja roteada segundo o atributo.Placing a route on the controller or the action makes it attribute routed. Ações que definem rotas de atributo não podem ser acessadas por meio das rotas convencionais e vice-versa.Actions that define attribute routes cannot be reached through the conventional routes and vice-versa. Qualquer atributo de rota no controlador faz com que todas as ações no atributo do controlador sejam roteadas.Any route attribute on the controller makes all actions in the controller attribute routed.

Roteamento de atributos e roteamento convencional usam o mesmo mecanismo de roteamento.Attribute routing and conventional routing use the same routing engine.

Geração de URL e valores de ambienteURL Generation and ambient values

Os aplicativos podem usar os recursos de geração de URL de roteamento para gerar links de URL para ações.Apps can use routing URL generation features to generate URL links to actions. A geração de URLs elimina URLs de codificação, tornando o código mais robusto e passível de manutenção.Generating URLs eliminates hardcoding URLs, making code more robust and maintainable. Esta seção se concentra nos recursos de geração de URL fornecidos pelo MVC e aborda apenas noções básicas de como funciona a geração de URL.This section focuses on the URL generation features provided by MVC and only cover basics of how URL generation works. Consulte Roteamento para obter uma descrição detalhada da geração de URL.See Routing for a detailed description of URL generation.

A IUrlHelper interface é o elemento subjacente da infraestrutura entre o MVC e o roteamento para a geração de URL.The IUrlHelper interface is the underlying element of infrastructure between MVC and routing for URL generation. Uma instância do IUrlHelper está disponível por meio da Url propriedade em controladores, exibições e componentes de exibição.An instance of IUrlHelper is available through the Url property in controllers, views, and view components.

No exemplo a seguir, a IUrlHelper interface é usada por meio da Controller.Url propriedade para gerar uma URL para outra ação.In the following example, the IUrlHelper interface is used through the Controller.Url property to generate a URL to another action.

public class UrlGenerationController : Controller
{
    public IActionResult Source()
    {
        // Generates /UrlGeneration/Destination
        var url = Url.Action("Destination");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }

    public IActionResult Destination()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

Se o aplicativo estiver usando a rota convencional padrão, o valor da url variável será a cadeia de caracteres do caminho da URL /UrlGeneration/Destination .If the app is using the default conventional route, the value of the url variable is the URL path string /UrlGeneration/Destination. Esse caminho de URL é criado pelo roteamento combinando:This URL path is created by routing by combining:

  • Os valores de rota da solicitação atual, que são chamados de valores de ambiente.The route values from the current request, which are called ambient values.
  • Os valores passados para Url.Action e substituindo esses valores no modelo de rota:The values passed to Url.Action and substituting those values into the route template:
ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}

result: /UrlGeneration/Destination

Cada parâmetro de rota no modelo de rota tem seu valor substituído por nomes correspondentes com os valores e os valores de ambiente.Each route parameter in the route template has its value substituted by matching names with the values and ambient values. Um parâmetro de rota que não tem um valor pode:A route parameter that doesn't have a value can:

  • Use um valor padrão se ele tiver um.Use a default value if it has one.
  • Será ignorado se for opcional.Be skipped if it's optional. Por exemplo, o id do modelo de rota {controller}/{action}/{id?} .For example, the id from the route template {controller}/{action}/{id?}.

A geração de URL falhará se qualquer parâmetro de rota necessário não tiver um valor correspondente.URL generation fails if any required route parameter doesn't have a corresponding value. Se a geração de URL falhar para uma rota, a rota seguinte será tentada até que todas as rotas tenham sido tentadas ou que uma correspondência seja encontrada.If URL generation fails for a route, the next route is tried until all routes have been tried or a match is found.

O exemplo anterior de Url.Action assume o Roteamento convencional.The preceding example of Url.Action assumes conventional routing. A geração de URL funciona de forma semelhante ao Roteamento de atributos, embora os conceitos sejam diferentes.URL generation works similarly with attribute routing, though the concepts are different. Com roteamento convencional:With conventional routing:

  • Os valores de rota são usados para expandir um modelo.The route values are used to expand a template.
  • Os valores de rota para controller e action geralmente aparecem nesse modelo.The route values for controller and action usually appear in that template. Isso funciona porque as URLs correspondidas pelo roteamento aderem a uma convenção.This works because the URLs matched by routing adhere to a convention.

O exemplo a seguir usa roteamento de atributo:The following example uses attribute routing:

public class UrlGenerationAttrController : Controller
{
    [HttpGet("custom")]
    public IActionResult Source()
    {
        var url = Url.Action("Destination");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }

    [HttpGet("custom/url/to/destination")]
    public IActionResult Destination()
    {
       return ControllerContext.MyDisplayRouteInfo();
    }
}

A Source ação no código anterior gera custom/url/to/destination .The Source action in the preceding code generates custom/url/to/destination.

LinkGeneratorfoi adicionado no ASP.NET Core 3,0 como uma alternativa ao IUrlHelper .LinkGenerator was added in ASP.NET Core 3.0 as an alternative to IUrlHelper. LinkGeneratoroferece funcionalidade semelhante, mas mais flexível.LinkGenerator offers similar but more flexible functionality. Cada método em IUrlHelper também tem uma família correspondente de métodos LinkGenerator .Each method on IUrlHelper has a corresponding family of methods on LinkGenerator as well.

Gerando URLs pelo nome da açãoGenerating URLs by action name

A URL. Action, LinkGenerator. GetPathByActione todas as sobrecargas relacionadas são projetadas para gerar o ponto de extremidade de destino especificando um nome de controlador e um nome de ação.Url.Action, LinkGenerator.GetPathByAction, and all related overloads all are designed to generate the target endpoint by specifying a controller name and action name.

Ao usar Url.Action , os valores de rota atuais para controller e action são fornecidos pelo tempo de execução:When using Url.Action, the current route values for controller and action are provided by the runtime:

  • O valor de controller e action são parte de valores de ambiente e valores.The value of controller and action are part of both ambient values and values. O método Url.Action sempre usa os valores atuais de action e controller e gera um caminho de URL que roteia para a ação atual.The method Url.Action always uses the current values of action and controller and generates a URL path that routes to the current action.

O roteamento tenta usar os valores em valores de ambiente para preencher as informações que não foram fornecidas durante a geração de uma URL.Routing attempts to use the values in ambient values to fill in information that wasn't provided when generating a URL. Considere uma rota como {a}/{b}/{c}/{d} com valores de ambiente { a = Alice, b = Bob, c = Carol, d = David } :Consider a route like {a}/{b}/{c}/{d} with ambient values { a = Alice, b = Bob, c = Carol, d = David }:

  • O roteamento tem informações suficientes para gerar uma URL sem valores adicionais.Routing has enough information to generate a URL without any additional values.
  • O roteamento tem informações suficientes porque todos os parâmetros de rota têm um valor.Routing has enough information because all route parameters have a value.

Se o valor { d = Donovan } for adicionado:If the value { d = Donovan } is added:

  • O valor { d = David } é ignorado.The value { d = David } is ignored.
  • O caminho de URL gerado é Alice/Bob/Carol/Donovan .The generated URL path is Alice/Bob/Carol/Donovan.

Aviso: os caminhos de URL são hierárquicos.Warning: URL paths are hierarchical. No exemplo anterior, se o valor { c = Cheryl } for adicionado:In the preceding example, if the value { c = Cheryl } is added:

  • Ambos os valores { c = Carol, d = David } são ignorados.Both of the values { c = Carol, d = David } are ignored.
  • Não há mais um valor para d e a geração de URL falha.There is no longer a value for d and URL generation fails.
  • Os valores desejados de c e d devem ser especificados para gerar uma URL.The desired values of c and d must be specified to generate a URL.

Talvez você espere atingir esse problema com a rota padrão {controller}/{action}/{id?} .You might expect to hit this problem with the default route {controller}/{action}/{id?}. Esse problema é raro na prática porque Url.Action o sempre especifica explicitamente controller um action valor e.This problem is rare in practice because Url.Action always explicitly specifies a controller and action value.

Várias sobrecargas de URL. Action usam um objeto de valores de rota para fornecer valores para parâmetros de rota diferentes de controller e action .Several overloads of Url.Action take a route values object to provide values for route parameters other than controller and action. O objeto de valores de rota é usado com frequência com id .The route values object is frequently used with id. Por exemplo, Url.Action("Buy", "Products", new { id = 17 }).For example, Url.Action("Buy", "Products", new { id = 17 }). O objeto de valores de rota:The route values object:

  • Por convenção geralmente é um objeto de tipo anônimo.By convention is usually an object of anonymous type.
  • Pode ser um IDictionary<> ou um poco).Can be an IDictionary<> or a POCO).

Qualquer valor de rota adicional que não corresponder aos parâmetros de rota será colocado na cadeia de caracteres de consulta.Any additional route values that don't match route parameters are put in the query string.

public IActionResult Index()
{
    var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
    return Content(url);
}

O código anterior gera /Products/Buy/17?color=red .The preceding code generates /Products/Buy/17?color=red.

O código a seguir gera uma URL absoluta:The following code generates an absolute URL:

public IActionResult Index2()
{
    var url = Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme);
    // Returns https://localhost:5001/Products/Buy/17
    return Content(url);
}

Para criar uma URL absoluta, use um dos seguintes:To create an absolute URL, use one of the following:

Gerar URLs por rotaGenerate URLs by route

O código anterior demonstrou a geração de uma URL passando o nome do controlador e da ação.The preceding code demonstrated generating a URL by passing in the controller and action name. IUrlHelpertambém fornece a família de métodos URL. RouteUrl .IUrlHelper also provides the Url.RouteUrl family of methods. Esses métodos são semelhantes a URL. Action, mas não copiam os valores atuais de action e controller para os valores de rota.These methods are similar to Url.Action, but they don't copy the current values of action and controller to the route values. O uso mais comum de Url.RouteUrl :The most common usage of Url.RouteUrl:

  • Especifica um nome de rota para gerar a URL.Specifies a route name to generate the URL.
  • Geralmente, não especifica um controlador ou um nome de ação.Generally doesn't specify a controller or action name.
public class UrlGeneration2Controller : Controller
{
    [HttpGet("")]
    public IActionResult Source()
    {
        var url = Url.RouteUrl("Destination_Route");
        return ControllerContext.MyDisplayRouteInfo("", $" URL = {url}");
    }

    [HttpGet("custom/url/to/destination2", Name = "Destination_Route")]
    public IActionResult Destination()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

O arquivo a seguir Razor gera um link HTML para Destination_Route :The following Razor file generates an HTML link to the Destination_Route:

<h1>Test Links</h1>

<ul>
    <li><a href="@Url.RouteUrl("Destination_Route")">Test Destination_Route</a></li>
</ul>

Gerar URLs em HTML eRazorGenerate URLs in HTML and Razor

IHtmlHelperfornece os HtmlHelper métodos HTML. BeginForm e HTML. ActionLink para gerar <form> e <a> elementos, respectivamente.IHtmlHelper provides the HtmlHelper methods Html.BeginForm and Html.ActionLink to generate <form> and <a> elements respectively. Esses métodos usam o método URL. Action para gerar uma URL e aceitam argumentos semelhantes.These methods use the Url.Action method to generate a URL and they accept similar arguments. O complementos Url.RouteUrl para HtmlHelper são Html.BeginRouteForm e Html.RouteLink, que têm uma funcionalidade semelhante.The Url.RouteUrl companions for HtmlHelper are Html.BeginRouteForm and Html.RouteLink which have similar functionality.

TagHelpers geram URLs por meio do TagHelper form e do TagHelper <a>.TagHelpers generate URLs through the form TagHelper and the <a> TagHelper. Ambos usam IUrlHelper para sua implementação.Both of these use IUrlHelper for their implementation. Consulte auxiliares de marca em formulários para obter mais informações.See Tag Helpers in forms for more information.

Nos modos de exibição, o IUrlHelper está disponível por meio da propriedade Url para qualquer geração de URL ad hoc não abordada acima.Inside views, the IUrlHelper is available through the Url property for any ad-hoc URL generation not covered by the above.

Geração de URL nos resultados da açãoURL generation in Action Results

Os exemplos anteriores mostraram o uso IUrlHelper de em um controlador.The preceding examples showed using IUrlHelper in a controller. O uso mais comum em um controlador é gerar uma URL como parte de um resultado de ação.The most common usage in a controller is to generate a URL as part of an action result.

As classes base ControllerBase e Controller fornecem métodos de conveniência para resultados de ação que fazem referência a outra ação.The ControllerBase and Controller base classes provide convenience methods for action results that reference another action. Um uso típico é redirecionar depois de aceitar a entrada do usuário:One typical usage is to redirect after accepting user input:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(int id, Customer customer)
{
    if (ModelState.IsValid)
    {
        // Update DB with new details.
        ViewData["Message"] = $"Successful edit of customer {id}";
        return RedirectToAction("Index");
    }
    return View(customer);
}

A ação resulta em métodos de fábrica como RedirectToAction e CreatedAtAction seguem um padrão semelhante para os métodos em IUrlHelper .The action results factory methods such as RedirectToAction and CreatedAtAction follow a similar pattern to the methods on IUrlHelper.

Caso especial para rotas convencionais dedicadasSpecial case for dedicated conventional routes

O Roteamento convencional pode usar um tipo especial de definição de rota chamada de rota convencional dedicada.Conventional routing can use a special kind of route definition called a dedicated conventional route. No exemplo a seguir, a rota chamada blog é uma rota convencional dedicada:In the following example, the route named blog is a dedicated conventional route:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "blog",
                pattern: "blog/{*article}",
                defaults: new { controller = "Blog", action = "Article" });
    endpoints.MapControllerRoute(name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
});

Usando as definições de rota anteriores, Url.Action("Index", "Home") o gera o caminho da URL / usando a default rota, mas por quê?Using the preceding route definitions, Url.Action("Index", "Home") generates the URL path / using the default route, but why? Você poderia imaginar que os valores de rota { controller = Home, action = Index } seriam suficientes para gerar uma URL usando blog e o resultado seria /blog?action=Index&controller=Home.You might guess the route values { controller = Home, action = Index } would be enough to generate a URL using blog, and the result would be /blog?action=Index&controller=Home.

As rotas convencionais dedicadas contam com um comportamento especial de valores padrão que não têm um parâmetro de rota correspondente que impede que a rota seja muito ávido com a geração de URL.Dedicated conventional routes rely on a special behavior of default values that don't have a corresponding route parameter that prevents the route from being too greedy with URL generation. Nesse caso, os valores padrão são { controller = Blog, action = Article } e nem controller ou action aparece como um parâmetro de rota.In this case the default values are { controller = Blog, action = Article }, and neither controller nor action appears as a route parameter. Quando o roteamento executa a geração de URL, os valores fornecidos devem corresponder aos valores padrão.When routing performs URL generation, the values provided must match the default values. A geração de URL usando blog falha porque os valores { controller = Home, action = Index } não correspondem { controller = Blog, action = Article } .URL generation using blog fails because the values { controller = Home, action = Index } don't match { controller = Blog, action = Article }. O roteamento, então, faz o fallback para tentar default, que é bem-sucedido.Routing then falls back to try default, which succeeds.

ÁreasAreas

As áreas são um recurso do MVC usado para organizar a funcionalidade relacionada em um grupo como separado:Areas are an MVC feature used to organize related functionality into a group as a separate:

  • Namespace de roteamento para ações do controlador.Routing namespace for controller actions.
  • Estrutura de pastas para exibições.Folder structure for views.

O uso de áreas permite que um aplicativo tenha vários controladores com o mesmo nome, desde que eles tenham áreas diferentes.Using areas allows an app to have multiple controllers with the same name, as long as they have different areas. O uso de áreas cria uma hierarquia para fins de roteamento, adicionando outro parâmetro de rota, area a controller e action.Using areas creates a hierarchy for the purpose of routing by adding another route parameter, area to controller and action. Esta seção discute como o roteamento interage com áreas.This section discusses how routing interacts with areas. Consulte áreas para obter detalhes sobre como as áreas são usadas com exibições.See Areas for details about how areas are used with views.

O exemplo a seguir configura o MVC para usar a rota convencional padrão e uma area rota para um area nome Blog :The following example configures MVC to use the default conventional route and an area route for an area named Blog:

app.UseEndpoints(endpoints =>
{
    endpoints.MapAreaControllerRoute("blog_route", "Blog",
        "Manage/{controller}/{action}/{id?}");
    endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});

No código anterior, MapAreaControllerRoute é chamado para criar o "blog_route" .In the preceding code, MapAreaControllerRoute is called to create the "blog_route". O segundo parâmetro, "Blog" , é o nome da área.The second parameter, "Blog", is the area name.

Ao fazer a correspondência de um caminho de URL como /Manage/Users/AddUser , a "blog_route" rota gera os valores de rota { area = Blog, controller = Users, action = AddUser } .When matching a URL path like /Manage/Users/AddUser, the "blog_route" route generates the route values { area = Blog, controller = Users, action = AddUser }. O area valor de rota é produzido por um valor padrão para area .The area route value is produced by a default value for area. A rota criada pelo MapAreaControllerRoute é equivalente à seguinte:The route created by MapAreaControllerRoute is equivalent to the following:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("blog_route", "Manage/{controller}/{action}/{id?}",
        defaults: new { area = "Blog" }, constraints: new { area = "Blog" });
    endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});

MapAreaControllerRoute cria uma rota usando um valor padrão e a restrição para area usando o nome da área fornecido, nesse caso, Blog.MapAreaControllerRoute creates a route using both a default value and constraint for area using the provided area name, in this case Blog. O valor padrão garante que a rota sempre produza { area = Blog, ... }, a restrição requer o valor { area = Blog, ... } para geração de URL.The default value ensures that the route always produces { area = Blog, ... }, the constraint requires the value { area = Blog, ... } for URL generation.

O roteamento convencional é dependente da ordem.Conventional routing is order-dependent. Em geral, as rotas com áreas devem ser posicionadas antes, pois são mais específicas do que as rotas sem uma área.In general, routes with areas should be placed earlier as they're more specific than routes without an area.

Usando o exemplo anterior, os valores de rota { area = Blog, controller = Users, action = AddUser } correspondem à seguinte ação:Using the preceding example, the route values { area = Blog, controller = Users, action = AddUser } match the following action:

using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}

O atributo [Area] é o que denota um controlador como parte de uma área.The [Area] attribute is what denotes a controller as part of an area. Esse controlador está na Blog área.This controller is in the Blog area. Os controladores sem um [Area] atributo não são membros de nenhuma área e não correspondem quando o area valor de rota é fornecido pelo roteamento.Controllers without an [Area] attribute are not members of any area, and do not match when the area route value is provided by routing. No exemplo a seguir, somente o primeiro controlador listado pode corresponder aos valores de rota { area = Blog, controller = Users, action = AddUser }.In the following example, only the first controller listed can match the route values { area = Blog, controller = Users, action = AddUser }.

using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace2
{
    // Matches { area = Zebra, controller = Users, action = AddUser }
    [Area("Zebra")]
    public class UsersController : Controller
    {
        // GET /zebra/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace3
{
    // Matches { area = string.Empty, controller = Users, action = AddUser }
    // Matches { area = null, controller = Users, action = AddUser }
    // Matches { controller = Users, action = AddUser }
    public class UsersController : Controller
    {
        // GET /users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }
    }
}

O namespace de cada controlador é mostrado aqui para fins de integridade.The namespace of each controller is shown here for completeness. Se os controladores anteriores usarem o mesmo namespace, um erro do compilador será gerado.If the preceding controllers uses the same namespace, a compiler error would be generated. Namespaces de classe não têm efeito sobre o roteamento do MVC.Class namespaces have no effect on MVC's routing.

Os primeiros dois controladores são membros de áreas e correspondem somente quando seus respectivos nomes de área são fornecidos pelo valor de rota area.The first two controllers are members of areas, and only match when their respective area name is provided by the area route value. O terceiro controlador não é um membro de nenhuma área e só pode corresponder quando nenhum valor para area for fornecido pelo roteamento.The third controller isn't a member of any area, and can only match when no value for area is provided by routing.

Em termos de não corresponder a nenhum valor, a ausência do valor de area é equivalente ao valor de area ser nulo ou uma cadeia de caracteres vazia.In terms of matching no value, the absence of the area value is the same as if the value for area were null or the empty string.

Ao executar uma ação dentro de uma área, o valor de rota para area está disponível como um valor de ambiente para roteamento a ser usado para a geração de URL.When executing an action inside an area, the route value for area is available as an ambient value for routing to use for URL generation. Isso significa que, por padrão, as áreas atuam como se fossem autoadesivas para a geração de URL, como demonstrado no exemplo a seguir.This means that by default areas act sticky for URL generation as demonstrated by the following sample.

app.UseEndpoints(endpoints =>
{
    endpoints.MapAreaControllerRoute(name: "duck_route", 
                                     areaName: "Duck",
                                     pattern: "Manage/{controller}/{action}/{id?}");
    endpoints.MapControllerRoute(name: "default",
                                 pattern: "Manage/{controller=Home}/{action=Index}/{id?}");
});
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace4
{
    [Area("Duck")]
    public class UsersController : Controller
    {
        // GET /Manage/users/GenerateURLInArea
        public IActionResult GenerateURLInArea()
        {
            // Uses the 'ambient' value of area.
            var url = Url.Action("Index", "Home");
            // Returns /Manage/Home/Index
            return Content(url);
        }

        // GET /Manage/users/GenerateURLOutsideOfArea
        public IActionResult GenerateURLOutsideOfArea()
        {
            // Uses the empty value for area.
            var url = Url.Action("Index", "Home", new { area = "" });
            // Returns /Manage
            return Content(url);
        }
    }
}

O código a seguir gera uma URL para /Zebra/Users/AddUser :The following code generates a URL to /Zebra/Users/AddUser:

public class HomeController : Controller
{
    public IActionResult About()
    {
        var url = Url.Action("AddUser", "Users", new { Area = "Zebra" });
        return Content($"URL: {url}");
    }

Definição de açãoAction definition

Os métodos públicos em um controlador, exceto aqueles com o atributo NonAction , são ações.Public methods on a controller, except those with the NonAction attribute, are actions.

Código de exemploSample code

Diagnóstico de depuraçãoDebug diagnostics

Para obter uma saída de diagnóstico de roteamento detalhada, defina Logging:LogLevel:Microsoft como Debug .For detailed routing diagnostic output, set Logging:LogLevel:Microsoft to Debug. No ambiente de desenvolvimento, defina o nível de log em appsettings.Development.jsem:In the development environment, set the log level in appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Debug",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

O ASP.NET Core MVC usa o middleware de Roteamento para fazer as correspondências das URLs de solicitações de entrada e mapeá-las para ações.ASP.NET Core MVC uses the Routing middleware to match the URLs of incoming requests and map them to actions. As rotas são definidas em atributos ou no código de inicialização.Routes are defined in startup code or attributes. Elas descrevem como deve ser feita a correspondência entre caminhos de URL e ações.Routes describe how URL paths should be matched to actions. As rotas também são usadas para gerar URLs (para links) enviados em resposta.Routes are also used to generate URLs (for links) sent out in responses.

As ações são roteadas convencionalmente ou segundo os atributos.Actions are either conventionally routed or attribute routed. Colocar uma rota no controlador ou na ação faz com que ela seja roteada segundo o atributo.Placing a route on the controller or the action makes it attribute routed. Para obter mais informações, consulte Roteamento misto.See Mixed routing for more information.

Este documento explicará as interações entre o MVC e o roteamento e como aplicativos MVC comuns usam recursos de roteamento.This document will explain the interactions between MVC and routing, and how typical MVC apps make use of routing features. Consulte Roteamento para obter detalhes sobre o roteamento avançado.See Routing for details on advanced routing.

Configurando o middleware de RoteamentoSetting up Routing Middleware

No método Configurar, você poderá ver código semelhante a:In your Configure method you may see code similar to:

app.UseMvc(routes =>
{
   routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});

Dentro da chamada para UseMvc, MapRoute é usado para criar uma única rota, que chamaremos de rota default.Inside the call to UseMvc, MapRoute is used to create a single route, which we'll refer to as the default route. A maioria dos aplicativos MVC usa uma rota com um modelo semelhante à rota default.Most MVC apps will use a route with a template similar to the default route.

O modelo de rota "{controller=Home}/{action=Index}/{id?}" pode corresponder a um caminho de URL como /Products/Details/5 e extrai os valores de rota { controller = Products, action = Details, id = 5 } gerando tokens para o caminho.The route template "{controller=Home}/{action=Index}/{id?}" can match a URL path like /Products/Details/5 and will extract the route values { controller = Products, action = Details, id = 5 } by tokenizing the path. O MVC tentará localizar um controlador chamado ProductsController e executar a ação Details:MVC will attempt to locate a controller named ProductsController and run the action Details:

public class ProductsController : Controller
{
   public IActionResult Details(int id) { ... }
}

Observe que, neste exemplo, o model binding usaria o valor de id = 5 para definir o parâmetro id como 5 ao invocar essa ação.Note that in this example, model binding would use the value of id = 5 to set the id parameter to 5 when invoking this action. Consulte Model binding para obter mais detalhes.See the Model Binding for more details.

Usando a rota default:Using the default route:

routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");

O modelo da rota:The route template:

  • {controller=Home} define Home como o controller padrão{controller=Home} defines Home as the default controller

  • {action=Index} define Index como o action padrão{action=Index} defines Index as the default action

  • {id?} define id como opcional{id?} defines id as optional

Parâmetros de rota opcionais e padrão não precisam estar presentes no caminho da URL para que haja uma correspondência.Default and optional route parameters don't need to be present in the URL path for a match. Consulte Referência de modelo de rota para obter uma descrição detalhada da sintaxe do modelo de rota.See Route Template Reference for a detailed description of route template syntax.

"{controller=Home}/{action=Index}/{id?}" pode corresponder ao caminho da URL / e produzirá os valores de rota { controller = Home, action = Index }."{controller=Home}/{action=Index}/{id?}" can match the URL path / and will produce the route values { controller = Home, action = Index }. Os valores de controller e action usam os valores padrão, id não produz um valor, uma vez que não há nenhum segmento correspondente no caminho da URL.The values for controller and action make use of the default values, id doesn't produce a value since there's no corresponding segment in the URL path. O MVC usaria esses valores de rota para selecionar a ação HomeController e Index:MVC would use these route values to select the HomeController and Index action:

public class HomeController : Controller
{
  public IActionResult Index() { ... }
}

Usando essa definição de controlador e modelo de rota, a ação HomeController.Index seria executada para qualquer um dos caminhos de URL a seguir:Using this controller definition and route template, the HomeController.Index action would be executed for any of the following URL paths:

  • /Home/Index/17

  • /Home/Index

  • /Home

  • /

O método de conveniência UseMvcWithDefaultRoute:The convenience method UseMvcWithDefaultRoute:

app.UseMvcWithDefaultRoute();

Pode ser usado para substituir:Can be used to replace:

app.UseMvc(routes =>
{
   routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});

UseMvc e UseMvcWithDefaultRoute adicionam uma instância de RouterMiddleware ao pipeline de middleware.UseMvc and UseMvcWithDefaultRoute add an instance of RouterMiddleware to the middleware pipeline. O MVC não interage diretamente com o middleware e usa o roteamento para tratar das solicitações.MVC doesn't interact directly with middleware, and uses routing to handle requests. O MVC é conectado às rotas por meio de uma instância de MvcRouteHandler.MVC is connected to the routes through an instance of MvcRouteHandler. O código dentro de UseMvc é semelhante ao seguinte:The code inside of UseMvc is similar to the following:

var routes = new RouteBuilder(app);

// Add connection to MVC, will be hooked up by calls to MapRoute.
routes.DefaultHandler = new MvcRouteHandler(...);

// Execute callback to register routes.
// routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");

// Create route collection and add the middleware.
app.UseRouter(routes.Build());

UseMvc não define diretamente nenhuma rota, ele adiciona um espaço reservado à coleção de rotas para a rota attribute.UseMvc doesn't directly define any routes, it adds a placeholder to the route collection for the attribute route. A sobrecarga UseMvc(Action<IRouteBuilder>) permite adicionar suas próprias rotas e também dá suporte ao roteamento de atributos.The overload UseMvc(Action<IRouteBuilder>) lets you add your own routes and also supports attribute routing. UseMvce todas as suas variações adicionam um espaço reservado para o atributo roteamento de atributo de rota está sempre disponível, independentemente de como você configura UseMvc .UseMvc and all of its variations add a placeholder for the attribute route - attribute routing is always available regardless of how you configure UseMvc. UseMvcWithDefaultRoute define uma rota padrão e dá suporte ao roteamento de atributos.UseMvcWithDefaultRoute defines a default route and supports attribute routing. A seção Roteamento de atributos inclui mais detalhes sobre o roteamento de atributos.The Attribute Routing section includes more details on attribute routing.

Roteamento convencionalConventional routing

A rota default:The default route:

routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");

O código anterior é um exemplo de roteamento convencional.The preceding code is an example of a conventional routing. Esse estilo é chamado de roteamento convencional porque ele estabelece uma Convenção para caminhos de URL:This style is called conventional routing because it establishes a convention for URL paths:

  • O primeiro segmento de caminho mapeia para o nome do controlador.The first path segment maps to the controller name.
  • O segundo mapeia para o nome da ação.The second maps to the action name.
  • O terceiro segmento é usado para um opcional id .The third segment is used for an optional id. idmapeia para uma entidade de modelo.id maps to a model entity.

Usando essa rota default, o caminho da URL /Products/List é mapeado para a ação ProductsController.List e /Blog/Article/17 é mapeado para BlogController.Article.Using this default route, the URL path /Products/List maps to the ProductsController.List action, and /Blog/Article/17 maps to BlogController.Article. Esse mapeamento é baseado somente nos nomes do controlador e da ação e não é baseado em namespaces, locais de arquivos de origem ou parâmetros de método.This mapping is based on the controller and action names only and isn't based on namespaces, source file locations, or method parameters.

Dica

Usar o roteamento convencional com a rota padrão permite compilar o aplicativo rapidamente sem precisar criar um novo padrão de URL para cada ação que você definir.Using conventional routing with the default route allows you to build the application quickly without having to come up with a new URL pattern for each action you define. Para um aplicativo com ações de estilo CRUD, ter consistência para as URLs em seus controladores pode ajudar a simplificar seu código e a tornar sua interface do usuário mais previsível.For an application with CRUD style actions, having consistency for the URLs across your controllers can help simplify your code and make your UI more predictable.

Aviso

O id é definido como opcional pelo modelo de rota, o que significa que suas ações podem ser executadas sem a ID fornecida como parte da URL.The id is defined as optional by the route template, meaning that your actions can execute without the ID provided as part of the URL. Normalmente, o que acontecerá se id for omitido da URL é que ele será definido como 0 pelo model binding e, dessa forma, não será encontrada no banco de dados nenhuma entidade correspondente a id == 0.Usually what will happen if id is omitted from the URL is that it will be set to 0 by model binding, and as a result no entity will be found in the database matching id == 0. O roteamento de atributos pode lhe proporcionar controle refinado para tornar a ID obrigatória para algumas ações e não para outras.Attribute routing can give you fine-grained control to make the ID required for some actions and not for others. Por convenção, a documentação incluirá parâmetros opcionais, como id, quando for provável que eles apareçam no uso correto.By convention the documentation will include optional parameters like id when they're likely to appear in correct usage.

Várias rotasMultiple routes

É possível adicionar várias rotas dentro de UseMvc adicionando mais chamadas para MapRoute.You can add multiple routes inside UseMvc by adding more calls to MapRoute. Fazer isso permite que você defina várias convenções ou que adicione rotas convencionais dedicadas a uma ação específica, como:Doing so allows you to define multiple conventions, or to add conventional routes that are dedicated to a specific action, such as:

app.UseMvc(routes =>
{
   routes.MapRoute("blog", "blog/{*article}",
            defaults: new { controller = "Blog", action = "Article" });
   routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});

A rota blog aqui é uma rota convencional dedicada, o que significa que ela usa o sistema de roteamento convencional, mas é dedicada a uma ação específica.The blog route here is a dedicated conventional route, meaning that it uses the conventional routing system, but is dedicated to a specific action. Como controller e action não aparecem no modelo de rota como parâmetros, eles só podem ter os valores padrão e, portanto, essa rota sempre será mapeada para a ação BlogController.Article.Since controller and action don't appear in the route template as parameters, they can only have the default values, and thus this route will always map to the action BlogController.Article.

As rotas na coleção de rotas são ordenadas e serão processadas na ordem em que forem adicionadas.Routes in the route collection are ordered, and will be processed in the order they're added. Portanto, neste exemplo, a rota blog será tentada antes da rota default.So in this example, the blog route will be tried before the default route.

Observação

Rotas convencionais dedicadas geralmente usam parâmetros de rota catch-all como {*article} para capturar a parte restante do caminho da URL.Dedicated conventional routes often use catch-all route parameters like {*article} to capture the remaining portion of the URL path. Isso pode fazer com que uma rota fique "muito ambiciosa", ou seja, que faça a correspondência com URLs que deveriam ser correspondidas com outras rotas.This can make a route 'too greedy' meaning that it matches URLs that you intended to be matched by other routes. Coloque as rotas "ambiciosas" mais adiante na tabela de rotas para solucionar esse problema.Put the 'greedy' routes later in the route table to solve this.

FallbackFallback

Como parte do processamento de solicitações, o MVC verificará se o valores das rotas podem ser usados para encontrar um controlador e uma ação em seu aplicativo.As part of request processing, MVC will verify that the route values can be used to find a controller and action in your application. Se os valores das rotas não corresponderem a uma ação, a rota não será considerada correspondente e a próxima rota será tentada.If the route values don't match an action then the route isn't considered a match, and the next route will be tried. Isso é chamado de fallback e sua finalidade é simplificar casos em que rotas convencionais se sobrepõem.This is called fallback, and it's intended to simplify cases where conventional routes overlap.

Desambiguação de açõesDisambiguating actions

Quando duas ações correspondem por meio do roteamento, o MVC precisa resolver a ambiguidade para escolher a "melhor" candidata ou lançar uma exceção.When two actions match through routing, MVC must disambiguate to choose the 'best' candidate or else throw an exception. Por exemplo:For example:

public class ProductsController : Controller
{
   public IActionResult Edit(int id) { ... }

   [HttpPost]
   public IActionResult Edit(int id, Product product) { ... }
}

Esse controlador define duas ações que fariam a correspondência entre caminho da URL /Products/Edit/17 e a os dados da rota { controller = Products, action = Edit, id = 17 }.This controller defines two actions that would match the URL path /Products/Edit/17 and route data { controller = Products, action = Edit, id = 17 }. Este é um padrão comum para controladores MVC em que Edit(int) mostra um formulário para editar um produto e Edit(int, Product) processa o formulário postado.This is a typical pattern for MVC controllers where Edit(int) shows a form to edit a product, and Edit(int, Product) processes the posted form. Para que isso seja possível, o MVC precisa escolher Edit(int, Product) quando a solicitação é um POST HTTP e Edit(int) quando o verbo HTTP é qualquer outra coisa.To make this possible MVC would need to choose Edit(int, Product) when the request is an HTTP POST and Edit(int) when the HTTP verb is anything else.

O HttpPostAttribute ([HttpPost]) é uma implementação de IActionConstraint que só permite que a ação seja selecionada quando o verbo HTTP é POST.The HttpPostAttribute ( [HttpPost] ) is an implementation of IActionConstraint that will only allow the action to be selected when the HTTP verb is POST. A presença de um IActionConstraint faz do Edit(int, Product) uma "melhor" correspondência do que Edit(int), portanto, Edit(int, Product) será tentado primeiro.The presence of an IActionConstraint makes the Edit(int, Product) a 'better' match than Edit(int), so Edit(int, Product) will be tried first.

Você só precisará gravar implementações personalizadas de IActionConstraint em cenários especializados, mas é importante compreender a função de atributos como HttpPostAttribute – atributos semelhantes são definidos para outros verbos HTTP.You will only need to write custom IActionConstraint implementations in specialized scenarios, but it's important to understand the role of attributes like HttpPostAttribute - similar attributes are defined for other HTTP verbs. No roteamento convencional, é comum que ações usem o mesmo nome de ação quando fazem parte de um fluxo de trabalho de show form -> submit form.In conventional routing it's common for actions to use the same action name when they're part of a show form -> submit form workflow. A conveniência desse padrão ficará mais aparente após você revisar a seção Noções básicas sobre IActionConstraint.The convenience of this pattern will become more apparent after reviewing the Understanding IActionConstraint section.

Se várias rotas corresponderem e o MVC não puder encontrar uma rota "melhor", ele gerará um AmbiguousActionException.If multiple routes match, and MVC can't find a 'best' route, it will throw an AmbiguousActionException.

Nomes de rotasRoute names

As cadeias de caracteres "blog" e "default" nos exemplos a seguir são nomes de rotas:The strings "blog" and "default" in the following examples are route names:

app.UseMvc(routes =>
{
   routes.MapRoute("blog", "blog/{*article}",
               defaults: new { controller = "Blog", action = "Article" });
   routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});

Os nomes de rotas dão a uma rota um nome lógico, de modo que a rota nomeada possa ser usada para geração de URL.The route names give the route a logical name so that the named route can be used for URL generation. Isso simplifica muito a criação de URLs quando a ordenação de rotas poderia complicá-la.This greatly simplifies URL creation when the ordering of routes could make URL generation complicated. Nomes de rotas devem ser exclusivos no nível do aplicativo.Route names must be unique application-wide.

Os nomes de rotas não têm impacto sobre a correspondência de URLs ou o tratamento de solicitações; eles são usados apenas para a geração de URLs.Route names have no impact on URL matching or handling of requests; they're used only for URL generation. Roteamento tem informações mais detalhadas sobre geração de URLs, incluindo a geração de URLs em auxiliares específicos do MVC.Routing has more detailed information on URL generation including URL generation in MVC-specific helpers.

Roteamento de atributoAttribute routing

O roteamento de atributo usa um conjunto de atributos para mapear ações diretamente para modelos de rota.Attribute routing uses a set of attributes to map actions directly to route templates. No exemplo a seguir, app.UseMvc(); é usado no método Configure e nenhuma rota é passada.In the following example, app.UseMvc(); is used in the Configure method and no route is passed. O HomeController corresponderá a um conjunto de URLs semelhantes ao que a rota padrão {controller=Home}/{action=Index}/{id?} corresponderia:The HomeController will match a set of URLs similar to what the default route {controller=Home}/{action=Index}/{id?} would match:

public class HomeController : Controller
{
   [Route("")]
   [Route("Home")]
   [Route("Home/Index")]
   public IActionResult Index()
   {
      return View();
   }
   [Route("Home/About")]
   public IActionResult About()
   {
      return View();
   }
   [Route("Home/Contact")]
   public IActionResult Contact()
   {
      return View();
   }
}

A ação HomeController.Index() será executada para qualquer um dos caminhos de URL /, /Home ou /Home/Index.The HomeController.Index() action will be executed for any of the URL paths /, /Home, or /Home/Index.

Observação

Este exemplo destaca uma diferença importante de programação entre o roteamento de atributo e o roteamento convencional.This example highlights a key programming difference between attribute routing and conventional routing. O roteamento de atributo requer mais entradas para especificar uma rota; a rota padrão convencional manipula as rotas de forma mais sucinta.Attribute routing requires more input to specify a route; the conventional default route handles routes more succinctly. No entanto, o roteamento de atributo permite (e exige) o controle preciso de quais modelos de rota se aplicam a cada ação.However, attribute routing allows (and requires) precise control of which route templates apply to each action.

Com o roteamento de atributo, o nome do controlador e os nomes de ação não desempenham nenhuma função quanto a qual ação é selecionada.With attribute routing the controller name and action names play no role in which action is selected. Este exemplo corresponderá as mesmas URLs que o exemplo anterior.This example will match the same URLs as the previous example.

public class MyDemoController : Controller
{
   [Route("")]
   [Route("Home")]
   [Route("Home/Index")]
   public IActionResult MyIndex()
   {
      return View("Index");
   }
   [Route("Home/About")]
   public IActionResult MyAbout()
   {
      return View("About");
   }
   [Route("Home/Contact")]
   public IActionResult MyContact()
   {
      return View("Contact");
   }
}

Observação

Os modelos de rota acima não definem parâmetros de rota para action, area e controller.The route templates above don't define route parameters for action, area, and controller. Na verdade, esses parâmetros de rota não são permitidos em rotas de atributo.In fact, these route parameters are not allowed in attribute routes. Uma vez que o modelo de rota já está associado a uma ação, não faria sentido analisar o nome da ação da URL.Since the route template is already associated with an action, it wouldn't make sense to parse the action name from the URL.

Roteamento de atributo com atributos Http[Verb]Attribute routing with Http[Verb] attributes

O roteamento de atributo também pode usar atributos Http[Verb], como HttpPostAttribute.Attribute routing can also make use of the Http[Verb] attributes such as HttpPostAttribute. Todos esses atributos podem aceitar um modelo de rota.All of these attributes can accept a route template. Este exemplo mostra duas ações que correspondem ao mesmo modelo de rota:This example shows two actions that match the same route template:

[HttpGet("/products")]
public IActionResult ListProducts()
{
   // ...
}

[HttpPost("/products")]
public IActionResult CreateProduct(...)
{
   // ...
}

Para um caminho de URL como /products, a ação ProductsApi.ListProducts será executada quando o verbo HTTP for GET e ProductsApi.CreateProduct será executado quando o verbo HTTP for POST.For a URL path like /products the ProductsApi.ListProducts action will be executed when the HTTP verb is GET and ProductsApi.CreateProduct will be executed when the HTTP verb is POST. Primeiro, o roteamento de atributo faz a correspondência da URL com o conjunto de modelos de rota definidos por atributos de rota.Attribute routing first matches the URL against the set of route templates defined by route attributes. Quando um modelo de rota for correspondente, restrições de IActionConstraint serão aplicadas para determinar quais ações podem ser executadas.Once a route template matches, IActionConstraint constraints are applied to determine which actions can be executed.

Dica

Ao criar uma API REST, é raro que você queira usar [Route(...)] em um método de ação, pois a ação aceitará todos os métodos http.When building a REST API, it's rare that you will want to use [Route(...)] on an action method as the action will accept all HTTP methods. É melhor usar o Http*Verb*Attributes mais específico para ser preciso quanto ao que tem suporte de sua API.It's better to use the more specific Http*Verb*Attributes to be precise about what your API supports. Espera-se que clientes de APIs REST saibam quais caminhos e verbos HTTP são mapeados para operações lógicas específicas.Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.

Como uma rota de atributo se aplica a uma ação específica, é fácil fazer com que parâmetros sejam obrigatórios como parte da definição do modelo de rota.Since an attribute route applies to a specific action, it's easy to make parameters required as part of the route template definition. Neste exemplo, id é obrigatório como parte do caminho da URL.In this example, id is required as part of the URL path.

public class ProductsApiController : Controller
{
   [HttpGet("/products/{id}", Name = "Products_List")]
   public IActionResult GetProduct(int id) { ... }
}

A ação ProductsApi.GetProduct(int) será executada para um caminho de URL como /products/3, mas não para um caminho de URL como /products.The ProductsApi.GetProduct(int) action will be executed for a URL path like /products/3 but not for a URL path like /products. Consulte Roteamento para obter uma descrição completa de modelos de rota e as opções relacionadas.See Routing for a full description of route templates and related options.

Nome da rotaRoute Name

O código a seguir define um nome da rota como Products_List:The following code defines a route name of Products_List:

public class ProductsApiController : Controller
{
   [HttpGet("/products/{id}", Name = "Products_List")]
   public IActionResult GetProduct(int id) { ... }
}

Nomes de rota podem ser usados para gerar uma URL com base em uma rota específica.Route names can be used to generate a URL based on a specific route. Nomes de rota não têm impacto sobre o comportamento de correspondência da URL e são usados somente para geração de URLs.Route names have no impact on the URL matching behavior of routing and are only used for URL generation. Nomes de rotas devem ser exclusivos no nível do aplicativo.Route names must be unique application-wide.

Observação

Compare isso com a rota padrão convencional, que define o parâmetro id como opcional ({id?}).Contrast this with the conventional default route, which defines the id parameter as optional ({id?}). Essa capacidade de especificar APIs de forma específica tem vantagens, como permitir que /products e /products/5 sejam expedidos para ações diferentes.This ability to precisely specify APIs has advantages, such as allowing /products and /products/5 to be dispatched to different actions.

Combinando rotasCombining routes

Para tornar o roteamento de atributo menos repetitivo, os atributos de rota no controlador são combinados com atributos de rota nas ações individuais.To make attribute routing less repetitive, route attributes on the controller are combined with route attributes on the individual actions. Modelos de rota definidos no controlador precedem modelos de rota nas ações. Any route templates defined on the controller are prepended to route templates on the actions. Colocar um atributo de rota no controlador foz com que todas as ações no controlador usem o roteamento de atributo.Placing a route attribute on the controller makes all actions in the controller use attribute routing.

[Route("products")]
public class ProductsApiController : Controller
{
   [HttpGet]
   public IActionResult ListProducts() { ... }

   [HttpGet("{id}")]
   public ActionResult GetProduct(int id) { ... }
}

Neste exemplo, o caminho de URL /products pode corresponder a ProductsApi.ListProducts e o caminho de URL /products/5 pode corresponder a ProductsApi.GetProduct(int).In this example the URL path /products can match ProductsApi.ListProducts, and the URL path /products/5 can match ProductsApi.GetProduct(int). Ambas as ações correspondem apenas a HTTP GET porque elas são marcadas com o HttpGetAttribute .Both of these actions only match HTTP GET because they're marked with the HttpGetAttribute.

Modelos de rota aplicados a uma ação, que começam com / ou ~/, não são combinados com modelos de rota aplicados ao controlador.Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller. Este exemplo corresponde a um conjunto de caminhos de URL semelhante à rota padrão.This example matches a set of URL paths similar to the default route.

[Route("Home")]
public class HomeController : Controller
{
    [Route("")]      // Combines to define the route template "Home"
    [Route("Index")] // Combines to define the route template "Home/Index"
    [Route("/")]     // Doesn't combine, defines the route template ""
    public IActionResult Index()
    {
        ViewData["Message"] = "Home index";
        var url = Url.Action("Index", "Home");
        ViewData["Message"] = "Home index" + "var url = Url.Action; =  " + url;
        return View();
    }

    [Route("About")] // Combines to define the route template "Home/About"
    public IActionResult About()
    {
        return View();
    }   
}

Ordenando rotas de atributosOrdering attribute routes

Ao contrário das rotas convencionais, que são executadas em uma ordem definida, o roteamento de atributo cria uma árvore e corresponde a todas as rotas simultaneamente.In contrast to conventional routes, which execute in a defined order, attribute routing builds a tree and matches all routes simultaneously. O comportamento é como se as entradas de rota fossem colocadas em uma ordem ideal; as rotas mais específicas têm uma chance de ser executadas antes das rotas mais gerais.This behaves as-if the route entries were placed in an ideal ordering; the most specific routes have a chance to execute before the more general routes.

Por exemplo, uma rota como blog/search/{topic} é mais específica que uma rota como blog/{*article}.For example, a route like blog/search/{topic} is more specific than a route like blog/{*article}. Em termos da lógica, a rota blog/search/{topic} é "executada" primeiro, por padrão, porque essa é a única ordem que faz sentido.Logically speaking the blog/search/{topic} route 'runs' first, by default, because that's the only sensible ordering. Usando o roteamento convencional, o desenvolvedor é responsável por colocar as rotas na ordem desejada.Using conventional routing, the developer is responsible for placing routes in the desired order.

Rotas de atributos podem configurar uma ordem, usando a propriedade Order de todos os atributos de rota fornecidos pela estrutura.Attribute routes can configure an order, using the Order property of all of the framework provided route attributes. As rotas são processadas segundo uma classificação crescente da propriedade Order.Routes are processed according to an ascending sort of the Order property. A ordem padrão é 0.The default order is 0. Uma rota definida usando Order = -1 será executada antes de rotas que não definem uma ordem.Setting a route using Order = -1 will run before routes that don't set an order. Uma rota definida usando Order = 1 será executada após a ordem das rotas padrão.Setting a route using Order = 1 will run after default route ordering.

Dica

Evite depender de Order.Avoid depending on Order. Se o seu espaço de URL exigir valores de ordem explícita para fazer o roteamento corretamente, provavelmente ele também será confuso para os clientes.If your URL-space requires explicit order values to route correctly, then it's likely confusing to clients as well. De modo geral, o roteamento de atributos selecionará a rota correta com a correspondência de URL.In general attribute routing will select the correct route with URL matching. Se a ordem padrão usada para a geração de URL não estiver funcionando, usar o nome da rota como uma substituição geralmente será mais simples do que aplicar a propriedade Order.If the default order used for URL generation isn't working, using route name as an override is usually simpler than applying the Order property.

RazorO roteamento de páginas e o roteamento do controlador MVC compartilham uma implementação. Pages routing and MVC controller routing share an implementation. As informações sobre a ordem de rota nos Razor Tópicos de páginas estão disponíveis em Razor páginas rota e convenções de aplicativo: ordem de rota.Information on route order in the Razor Pages topics is available at Razor Pages route and app conventions: Route order.

Substituição de token em modelos de rota ([controlador] [ação] [área])Token replacement in route templates ([controller], [action], [area])

Para sua conveniência, as rotas de atributo dão suporte à substituição de token ao colocar um token entre colchetes ( [ , ] ).For convenience, attribute routes support token replacement by enclosing a token in square-brackets ([, ]). Os tokens [action], [area] e [controller] são substituídos pelos valores do nome da ação, do nome da área e do nome do controlador da ação em que a rota é definida.The tokens [action], [area], and [controller] are replaced with the values of the action name, area name, and controller name from the action where the route is defined. No exemplo a seguir, as ações correspondem a caminhos de URL conforme descrito nos comentários:In the following example, the actions match URL paths as described in the comments:

[Route("[controller]/[action]")]
public class ProductsController : Controller
{
    [HttpGet] // Matches '/Products/List'
    public IActionResult List() {
        // ...
    }

    [HttpGet("{id}")] // Matches '/Products/Edit/{id}'
    public IActionResult Edit(int id) {
        // ...
    }
}

A substituição de token ocorre como a última etapa da criação das rotas de atributo.Token replacement occurs as the last step of building the attribute routes. O exemplo acima se comportará da mesma forma que o código a seguir:The above example will behave the same as the following code:


public class ProductsController : Controller
{
    [HttpGet("[controller]/[action]")] // Matches '/Products/List'
    public IActionResult List() {
        // ...
    }

    [HttpGet("[controller]/[action]/{id}")] // Matches '/Products/Edit/{id}'
    public IActionResult Edit(int id) {
        // ...
    }
}

Rotas de atributo também podem ser combinadas com herança.Attribute routes can also be combined with inheritance. Isso é especialmente eficiente em combinação com a substituição de token.This is particularly powerful combined with token replacement.

[Route("api/[controller]")]
public abstract class MyBaseController : Controller { ... }

public class ProductsController : MyBaseController
{
   [HttpGet] // Matches '/api/Products'
   public IActionResult List() { ... }

   [HttpPut("{id}")] // Matches '/api/Products/{id}'
   public IActionResult Edit(int id) { ... }
}

A substituição de token também se aplica a nomes de rota definidos por rotas de atributo.Token replacement also applies to route names defined by attribute routes. [Route("[controller]/[action]", Name="[controller]_[action]")] gera um nome de rota exclusivo para cada ação.[Route("[controller]/[action]", Name="[controller]_[action]")] generates a unique route name for each action.

Para corresponder ao delimitador de substituição de token literal [ ou ], faça seu escape repetindo o caractere ([[ ou ]]).To match the literal token replacement delimiter [ or ], escape it by repeating the character ([[ or ]]).

Usar um transformador de parâmetro para personalizar a substituição de tokenUse a parameter transformer to customize token replacement

A substituição do token pode ser personalizada usando um transformador de parâmetro.Token replacement can be customized using a parameter transformer. Um transformador de parâmetro implementa IOutboundParameterTransformer e transforma o valor dos parâmetros.A parameter transformer implements IOutboundParameterTransformer and transforms the value of parameters. Por exemplo, um transformador de parâmetro SlugifyParameterTransformer personalizado muda o valor de rota SubscriptionManagement para subscription-management.For example, a custom SlugifyParameterTransformer parameter transformer changes the SubscriptionManagement route value to subscription-management.

O RouteTokenTransformerConvention é uma convenção de modelo de aplicativo que:The RouteTokenTransformerConvention is an application model convention that:

  • Aplica um transformador de parâmetro a todas as rotas de atributo em um aplicativo.Applies a parameter transformer to all attribute routes in an application.
  • Personaliza os valores de token de rota de atributo conforme eles são substituídos.Customizes the attribute route token values as they are replaced.
public class SubscriptionManagementController : Controller
{
    [HttpGet("[controller]/[action]")] // Matches '/subscription-management/list-all'
    public IActionResult ListAll() { ... }
}

O RouteTokenTransformerConvention está registrado como uma opção em ConfigureServices.The RouteTokenTransformerConvention is registered as an option in ConfigureServices.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Conventions.Add(new RouteTokenTransformerConvention(
                                     new SlugifyParameterTransformer()));
    });
}

public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object value)
    {
        if (value == null) { return null; }

        // Slugify value
        return Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
    }
}

Várias rotasMultiple Routes

O roteamento de atributo dá suporte à definição de várias rotas que atingem a mesma ação.Attribute routing supports defining multiple routes that reach the same action. O uso mais comum desse recurso é para simular o comportamento da rota convencional padrão, conforme mostrado no exemplo a seguir:The most common usage of this is to mimic the behavior of the default conventional route as shown in the following example:

[Route("[controller]")]
public class ProductsController : Controller
{
   [Route("")]     // Matches 'Products'
   [Route("Index")] // Matches 'Products/Index'
   public IActionResult Index()
}

Colocar vários atributos de rota no controlador significa que cada um deles será combinado com cada um dos atributos de rota nos métodos de ação.Putting multiple route attributes on the controller means that each one will combine with each of the route attributes on the action methods.

[Route("Store")]
[Route("[controller]")]
public class ProductsController : Controller
{
   [HttpPost("Buy")]     // Matches 'Products/Buy' and 'Store/Buy'
   [HttpPost("Checkout")] // Matches 'Products/Checkout' and 'Store/Checkout'
   public IActionResult Buy()
}

Quando vários atributos de rota (que implementam IActionConstraint) são colocados em uma ação, cada restrição da ação combina com o modelo de rota do atributo que a definiu.When multiple route attributes (that implement IActionConstraint) are placed on an action, then each action constraint combines with the route template from the attribute that defined it.

[Route("api/[controller]")]
public class ProductsController : Controller
{
   [HttpPut("Buy")]      // Matches PUT 'api/Products/Buy'
   [HttpPost("Checkout")] // Matches POST 'api/Products/Checkout'
   public IActionResult Buy()
}

Dica

Embora o uso de várias rotas em ações possa parecer eficaz, é melhor manter o espaço de URL de seu aplicativo simples e bem definido.While using multiple routes on actions can seem powerful, it's better to keep your application's URL space simple and well-defined. Use várias rotas em ações somente quando for necessário; por exemplo, para dar suporte a clientes existentes.Use multiple routes on actions only where needed, for example to support existing clients.

Especificando parâmetros opcionais, valores padrão e restrições da rota de atributoSpecifying attribute route optional parameters, default values, and constraints

Rotas de atributo dão suporte à mesma sintaxe embutida que as rotas convencionais para especificar parâmetros opcionais, valores padrão e restrições.Attribute routes support the same inline syntax as conventional routes to specify optional parameters, default values, and constraints.

[HttpPost("product/{id:int}")]
public IActionResult ShowProduct(int id)
{
   // ...
}

Consulte Referência de modelo de rota para obter uma descrição detalhada da sintaxe do modelo de rota.See Route Template Reference for a detailed description of route template syntax.

Atributos de rota personalizados usando IRouteTemplateProviderCustom route attributes using IRouteTemplateProvider

Todos os atributos de rota fornecidos na estrutura ( [Route(...)], [HttpGet(...)] etc.) implementam a interface IRouteTemplateProvider.All of the route attributes provided in the framework ( [Route(...)], [HttpGet(...)] , etc.) implement the IRouteTemplateProvider interface. O MVC procura atributos em classes de controlador e métodos de ação quando o aplicativo é iniciado e usa aqueles que implementam IRouteTemplateProvider para criar o conjunto inicial de rotas.MVC looks for attributes on controller classes and action methods when the app starts and uses the ones that implement IRouteTemplateProvider to build the initial set of routes.

Você pode implementar IRouteTemplateProvider para definir seus próprios atributos de rota.You can implement IRouteTemplateProvider to define your own route attributes. Cada IRouteTemplateProvider permite definir uma única rota com um nome, uma ordem e um modelo de rota personalizado:Each IRouteTemplateProvider allows you to define a single route with a custom route template, order, and name:

public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider
{
   public string Template => "api/[controller]";

   public int? Order { get; set; }

   public string Name { get; set; }
}

O atributo do exemplo acima configura automaticamente o Template como "api/[controller]" quando [MyApiController] é aplicado.The attribute from the above example automatically sets the Template to "api/[controller]" when [MyApiController] is applied.

Usando o Modelo de Aplicativo para personalizar rotas de atributoUsing Application Model to customize attribute routes

O modelo de aplicativo é um modelo de objeto criado durante a inicialização com todos os metadados usados pelo MVC para rotear e executar suas ações.The application model is an object model created at startup with all of the metadata used by MVC to route and execute your actions. O modelo de aplicativo inclui todos os dados reunidos dos atributos de rota (por meio de IRouteTemplateProvider).The application model includes all of the data gathered from route attributes (through IRouteTemplateProvider). Você pode escrever convenções para modificar o modelo do aplicativo no momento da inicialização para personalizar o comportamento do roteamento.You can write conventions to modify the application model at startup time to customize how routing behaves. Esta seção mostra um exemplo simples de personalização de roteamento usando o modelo de aplicativo.This section shows a simple example of customizing routing using application model.

using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Linq;
using System.Text;
public class NamespaceRoutingConvention : IControllerModelConvention
{
    private readonly string _baseNamespace;

    public NamespaceRoutingConvention(string baseNamespace)
    {
        _baseNamespace = baseNamespace;
    }

    public void Apply(ControllerModel controller)
    {
        var hasRouteAttributes = controller.Selectors.Any(selector =>
                                                selector.AttributeRouteModel != null);
        if (hasRouteAttributes)
        {
            // This controller manually defined some routes, so treat this 
            // as an override and not apply the convention here.
            return;
        }

        // Use the namespace and controller name to infer a route for the controller.
        //
        // Example:
        //
        //  controller.ControllerTypeInfo ->    "My.Application.Admin.UsersController"
        //  baseNamespace ->                    "My.Application"
        //
        //  template =>                         "Admin/[controller]"
        //
        // This makes your routes roughly line up with the folder structure of your project.
        //
        var namespc = controller.ControllerType.Namespace;
        if (namespc == null)
            return;
        var template = new StringBuilder();
        template.Append(namespc, _baseNamespace.Length + 1,
                        namespc.Length - _baseNamespace.Length - 1);
        template.Replace('.', '/');
        template.Append("/[controller]");

        foreach (var selector in controller.Selectors)
        {
            selector.AttributeRouteModel = new AttributeRouteModel()
            {
                Template = template.ToString()
            };
        }
    }
}

Roteamento misto: roteamento de atributo versus roteamento convencionalMixed routing: Attribute routing vs conventional routing

Aplicativos MVC podem combinar o uso do roteamento convencional e do roteamento de atributo.MVC applications can mix the use of conventional routing and attribute routing. É comum usar rotas convencionais para controladores que servem páginas HTML para navegadores e usar o roteamento de atributo para controladores que servem APIs REST.It's typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs.

As ações são roteadas convencionalmente ou segundo os atributos.Actions are either conventionally routed or attribute routed. Colocar uma rota no controlador ou na ação faz com que ela seja roteada segundo o atributo.Placing a route on the controller or the action makes it attribute routed. Ações que definem rotas de atributo não podem ser acessadas por meio das rotas convencionais e vice-versa.Actions that define attribute routes cannot be reached through the conventional routes and vice-versa. Qualquer atributo de rota no controlador faz com que todas as ações no atributo de controlador sejam roteadas.Any route attribute on the controller makes all actions in the controller attribute routed.

Observação

O que diferencia os dois tipos de sistemas de roteamento é o processo aplicado após uma URL corresponder a um modelo de rota.What distinguishes the two types of routing systems is the process applied after a URL matches a route template. No roteamento convencional, os valores de rota da correspondência são usados para escolher a ação e o controlador em uma tabela de pesquisa com todas as ações roteadas convencionais.In conventional routing, the route values from the match are used to choose the action and controller from a lookup table of all conventional routed actions. No roteamento de atributo, cada modelo já está associado a uma ação e nenhuma pesquisa adicional é necessária.In attribute routing, each template is already associated with an action, and no further lookup is needed.

Segmentos complexosComplex segments

Segmentos complexos (por exemplo, [Route("/dog{token}cat")]), são processados combinando literais da direita para a esquerda de uma maneira não Greedy.Complex segments (for example, [Route("/dog{token}cat")]), are processed by matching up literals from right to left in a non-greedy way. Veja o código-fonte para obter uma descrição.See the source code for a description. Para obter mais informações, confira esta edição.For more information, see this issue.

Geração de URLURL Generation

Aplicativos MVC podem usar os recursos de geração de URL do roteamento para gerar links de URL para ações.MVC applications can use routing's URL generation features to generate URL links to actions. Gerar URLs elimina a necessidade de codificar URLs, tornando seu código mais robusto e sustentável.Generating URLs eliminates hardcoding URLs, making your code more robust and maintainable. Esta seção tem como foco os recursos de geração de URL fornecidos pelo MVC e só aborda as noções básicas de como a geração de URL funciona.This section focuses on the URL generation features provided by MVC and will only cover basics of how URL generation works. Consulte Roteamento para obter uma descrição detalhada da geração de URL.See Routing for a detailed description of URL generation.

A interface IUrlHelper é a parte subjacente da infraestrutura entre o MVC e o roteamento para geração de URL.The IUrlHelper interface is the underlying piece of infrastructure between MVC and routing for URL generation. Você encontrará uma instância de IUrlHelper disponível por meio da propriedade Url em controladores, exibições e componentes de exibição.You'll find an instance of IUrlHelper available through the Url property in controllers, views, and view components.

Neste exemplo, a interface IUrlHelper é usada por meio a propriedade Controller.Url para gerar uma URL para outra ação.In this example, the IUrlHelper interface is used through the Controller.Url property to generate a URL to another action.

using Microsoft.AspNetCore.Mvc;

public class UrlGenerationController : Controller
{
    public IActionResult Source()
    {
        // Generates /UrlGeneration/Destination
        var url = Url.Action("Destination");
        return Content($"Go check out {url}, it's really great.");
    }

    public IActionResult Destination()
    {
        return View();
    }
}

Se o aplicativo estiver usando a rota convencional padrão, o valor da variável url será a cadeia de caracteres do caminho de URL /UrlGeneration/Destination.If the application is using the default conventional route, the value of the url variable will be the URL path string /UrlGeneration/Destination. Esse caminho de URL é criado pelo roteamento combinando os valores de rota da solicitação atual (valores de ambiente) com os valores passados para Url.Action e substituindo esses valores no modelo de rota:This URL path is created by routing by combining the route values from the current request (ambient values), with the values passed to Url.Action and substituting those values into the route template:

ambient values: { controller = "UrlGeneration", action = "Source" }
values passed to Url.Action: { controller = "UrlGeneration", action = "Destination" }
route template: {controller}/{action}/{id?}

result: /UrlGeneration/Destination

Cada parâmetro de rota no modelo de rota tem seu valor substituído por nomes correspondentes com os valores e os valores de ambiente.Each route parameter in the route template has its value substituted by matching names with the values and ambient values. Um parâmetro de rota que não tem um valor pode usar um valor padrão se houver um ou pode ser ignorado se for opcional (como no caso de id neste exemplo).A route parameter that doesn't have a value can use a default value if it has one, or be skipped if it's optional (as in the case of id in this example). A geração de URL falhará se qualquer parâmetro de rota obrigatório não tiver um valor correspondente.URL generation will fail if any required route parameter doesn't have a corresponding value. Se a geração de URL falhar para uma rota, a rota seguinte será tentada até que todas as rotas tenham sido tentadas ou que uma correspondência seja encontrada.If URL generation fails for a route, the next route is tried until all routes have been tried or a match is found.

O exemplo de Url.Action acima pressupõe que o roteamento seja convencional, mas a geração de URL funciona de forma semelhante com o roteamento de atributo, embora os conceitos sejam diferentes.The example of Url.Action above assumes conventional routing, but URL generation works similarly with attribute routing, though the concepts are different. Com o roteamento convencional, os valores de rota são usados para expandir um modelo e os valores de rota para controller e action normalmente são exibidos no modelo – isso funciona porque as URLs correspondidas pelo roteamento aderem a uma convenção.With conventional routing, the route values are used to expand a template, and the route values for controller and action usually appear in that template - this works because the URLs matched by routing adhere to a convention. No roteamento de atributo, os valores de rota para controller e action não podem ser exibidos no modelo; em vez disso, eles são usados para pesquisar o modelo a ser usado.In attribute routing, the route values for controller and action are not allowed to appear in the template - they're instead used to look up which template to use.

Este exemplo usa o roteamento de atributo:This example uses attribute routing:

// In Startup class
public void Configure(IApplicationBuilder app)
{
    app.UseMvc();
}
using Microsoft.AspNetCore.Mvc;

public class UrlGenerationController : Controller
{
    [HttpGet("")]
    public IActionResult Source()
    {
        var url = Url.Action("Destination"); // Generates /custom/url/to/destination
        return Content($"Go check out {url}, it's really great.");
    }

    [HttpGet("custom/url/to/destination")]
    public IActionResult Destination() {
        return View();
    }
}

O MVC cria uma tabela de pesquisa de todas as ações de atributo roteadas e faz a correspondência dos valores de controller e action para selecionar o modelo de rota a ser usado para geração de URL.MVC builds a lookup table of all attribute routed actions and will match the controller and action values to select the route template to use for URL generation. Na amostra acima, custom/url/to/destination é gerado.In the sample above, custom/url/to/destination is generated.

Gerando URLs pelo nome da açãoGenerating URLs by action name

Url.Action (IUrlHelper .Url.Action (IUrlHelper . Action) e todas as sobrecargas relacionadas são baseadas na ideia de que você deseja especificar ao que está vinculando, especificando um nome do controlador e um nome da ação.Action) and all related overloads all are based on that idea that you want to specify what you're linking to by specifying a controller name and action name.

Observação

Ao usar Url.Action, os valores de rota atuais para controller e action são especificados para você – o valor de controller e action fazem parte de valores de ambiente **e de ** valores.When using Url.Action, the current route values for controller and action are specified for you - the value of controller and action are part of both ambient values and values. O método Url.Action sempre usa os valores atuais de action e controller e gera um caminho de URL que roteia para a ação atual.The method Url.Action, always uses the current values of action and controller and will generate a URL path that routes to the current action.

O roteamento tenta usar os valores em valores de ambiente para preencher informações que você não forneceu ao gerar uma URL.Routing attempts to use the values in ambient values to fill in information that you didn't provide when generating a URL. Usando uma rota como {a}/{b}/{c}/{d} e valores de ambiente { a = Alice, b = Bob, c = Carol, d = David }, o roteamento tem informações suficientes para gerar uma URL sem valores adicionais – uma vez que todos os parâmetros de rota têm um valor.Using a route like {a}/{b}/{c}/{d} and ambient values { a = Alice, b = Bob, c = Carol, d = David }, routing has enough information to generate a URL without any additional values - since all route parameters have a value. Se você tiver adicionado o valor { d = Donovan }, o valor { d = David } será ignorado e o caminho de URL gerado será Alice/Bob/Carol/Donovan.If you added the value { d = Donovan }, the value { d = David } would be ignored, and the generated URL path would be Alice/Bob/Carol/Donovan.

Aviso

Caminhos de URL são hierárquicos.URL paths are hierarchical. No exemplo acima, se você tiver adicionado o valor { c = Cheryl }, ambos os valores { c = Carol, d = David } serão ignorados.In the example above, if you added the value { c = Cheryl }, both of the values { c = Carol, d = David } would be ignored. Nesse caso, não teremos mais um valor para d e a geração de URL falhará.In this case we no longer have a value for d and URL generation will fail. Você precisaria especificar o valor desejado de c e d.You would need to specify the desired value of c and d. Você pode esperar se deparar com esse problema com a rota padrão ({controller}/{action}/{id?}) – mas raramente encontrará esse comportamento na prática, pois Url.Action sempre especificará explicitamente um valor de controller e action.You might expect to hit this problem with the default route ({controller}/{action}/{id?}) - but you will rarely encounter this behavior in practice as Url.Action will always explicitly specify a controller and action value.

Sobrecargas maiores de Url.Action também usam um objeto adicional de valores de rota para fornecer valores para parâmetros de rota diferentes de controller e action.Longer overloads of Url.Action also take an additional route values object to provide values for route parameters other than controller and action. É mais comum ver isso com id como Url.Action("Buy", "Products", new { id = 17 }).You will most commonly see this used with id like Url.Action("Buy", "Products", new { id = 17 }). Por convenção, o objeto de valores de rota geralmente é um objeto de tipo anônimo, mas também pode ser um IDictionary<> ou um objeto .NET simples.By convention the route values object is usually an object of anonymous type, but it can also be an IDictionary<> or a plain old .NET object. Qualquer valor de rota adicional que não corresponder aos parâmetros de rota será colocado na cadeia de caracteres de consulta.Any additional route values that don't match route parameters are put in the query string.

using Microsoft.AspNetCore.Mvc;

public class TestController : Controller
{
    public IActionResult Index()
    {
        // Generates /Products/Buy/17?color=red
        var url = Url.Action("Buy", "Products", new { id = 17, color = "red" });
        return Content(url);
    }
}

Dica

Para criar uma URL absoluta, use uma sobrecarga que aceita um protocol: Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme)To create an absolute URL, use an overload that accepts a protocol: Url.Action("Buy", "Products", new { id = 17 }, protocol: Request.Scheme)

Gerando URLs pela rotaGenerating URLs by route

O código acima demonstrou a geração de uma URL passando o nome do controlador e da ação.The code above demonstrated generating a URL by passing in the controller and action name. IUrlHelper também fornece a família de métodos Url.RouteUrl.IUrlHelper also provides the Url.RouteUrl family of methods. Esses métodos são semelhantes a Url.Action, mas não copiam os valores atuais de action e controller para os valores de rota.These methods are similar to Url.Action, but they don't copy the current values of action and controller to the route values. O uso mais comum é especificar um nome de rota para usar uma rota específica para gerar a URL, geralmente sem especificar um nome de controlador ou de ação.The most common usage is to specify a route name to use a specific route to generate the URL, generally without specifying a controller or action name.

using Microsoft.AspNetCore.Mvc;

public class UrlGenerationController : Controller
{
    [HttpGet("")]
    public IActionResult Source()
    {
        var url = Url.RouteUrl("Destination_Route"); // Generates /custom/url/to/destination
        return Content($"See {url}, it's really great.");
    }

    [HttpGet("custom/url/to/destination", Name = "Destination_Route")]
    public IActionResult Destination() {
        return View();
    }
}

Gerar URLs em HTMLGenerating URLs in HTML

IHtmlHelper fornece o métodos Html.BeginForm e Html.ActionLink de HtmlHelper para gerar elementos <form> e <a> respectivamente.IHtmlHelper provides the HtmlHelper methods Html.BeginForm and Html.ActionLink to generate <form> and <a> elements respectively. Esses métodos usam o método Url.Action para gerar uma URL e aceitam argumentos semelhantes.These methods use the Url.Action method to generate a URL and they accept similar arguments. O complementos Url.RouteUrl para HtmlHelper são Html.BeginRouteForm e Html.RouteLink, que têm uma funcionalidade semelhante.The Url.RouteUrl companions for HtmlHelper are Html.BeginRouteForm and Html.RouteLink which have similar functionality.

TagHelpers geram URLs por meio do TagHelper form e do TagHelper <a>.TagHelpers generate URLs through the form TagHelper and the <a> TagHelper. Ambos usam IUrlHelper para sua implementação.Both of these use IUrlHelper for their implementation. Consulte Trabalhando com Formulários para obter mais informações.See Working with Forms for more information.

Nos modos de exibição, o IUrlHelper está disponível por meio da propriedade Url para qualquer geração de URL ad hoc não abordada acima.Inside views, the IUrlHelper is available through the Url property for any ad-hoc URL generation not covered by the above.

Gerando URLS nos resultados da açãoGenerating URLS in Action Results

Os exemplos acima mostraram o uso de IUrlHelper em um controlador, enquanto o uso mais comum em um controlador é gerar uma URL como parte do resultado de uma ação.The examples above have shown using IUrlHelper in a controller, while the most common usage in a controller is to generate a URL as part of an action result.

As classes base ControllerBase e Controller fornecem métodos de conveniência para resultados de ação que fazem referência a outra ação.The ControllerBase and Controller base classes provide convenience methods for action results that reference another action. Um uso típico é para redirecionar após aceitar a entrada do usuário.One typical usage is to redirect after accepting user input.

public IActionResult Edit(int id, Customer customer)
{
    if (ModelState.IsValid)
    {
        // Update DB with new details.
        return RedirectToAction("Index");
    }
    return View(customer);
}

Os métodos de fábrica dos resultados da ação seguem um padrão semelhante aos métodos em IUrlHelper.The action results factory methods follow a similar pattern to the methods on IUrlHelper.

Caso especial para rotas convencionais dedicadasSpecial case for dedicated conventional routes

O roteamento convencional pode usar um tipo especial de definição de rota chamado rota convencional dedicada.Conventional routing can use a special kind of route definition called a dedicated conventional route. No exemplo a seguir, a rota chamada blog é uma rota convencional dedicada.In the example below, the route named blog is a dedicated conventional route.

app.UseMvc(routes =>
{
    routes.MapRoute("blog", "blog/{*article}",
        defaults: new { controller = "Blog", action = "Article" });
    routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
});

Usando essas definições de rota, Url.Action("Index", "Home") gerará o caminho de URL / com a rota default, mas por quê?Using these route definitions, Url.Action("Index", "Home") will generate the URL path / with the default route, but why? Você poderia imaginar que os valores de rota { controller = Home, action = Index } seriam suficientes para gerar uma URL usando blog e o resultado seria /blog?action=Index&controller=Home.You might guess the route values { controller = Home, action = Index } would be enough to generate a URL using blog, and the result would be /blog?action=Index&controller=Home.

Rotas convencionais dedicadas dependem de um comportamento especial de valores padrão que não têm um parâmetro de rota correspondente que impeça que a rota seja "muito ambiciosa" com a geração de URLs.Dedicated conventional routes rely on a special behavior of default values that don't have a corresponding route parameter that prevents the route from being "too greedy" with URL generation. Nesse caso, os valores padrão são { controller = Blog, action = Article } e nem controller ou action aparece como um parâmetro de rota.In this case the default values are { controller = Blog, action = Article }, and neither controller nor action appears as a route parameter. Quando o roteamento executa a geração de URL, os valores fornecidos devem corresponder aos valores padrão.When routing performs URL generation, the values provided must match the default values. A geração de URL usando blog falhará porque os valores de { controller = Home, action = Index } não correspondem a { controller = Blog, action = Article }.URL generation using blog will fail because the values { controller = Home, action = Index } don't match { controller = Blog, action = Article }. O roteamento, então, faz o fallback para tentar default, que é bem-sucedido.Routing then falls back to try default, which succeeds.

ÁreasAreas

Áreas são um recurso do MVC usado para organizar funcionalidades relacionadas em um grupo como um namespace de roteamento (para ações do controlador) e estrutura de pasta (para exibições) separada.Areas are an MVC feature used to organize related functionality into a group as a separate routing-namespace (for controller actions) and folder structure (for views). O uso de áreas permite que um aplicativo tenha vários controladores com o mesmo nome, desde que tenham áreas diferentes.Using areas allows an application to have multiple controllers with the same name - as long as they have different areas. O uso de áreas cria uma hierarquia para fins de roteamento, adicionando outro parâmetro de rota, area a controller e action.Using areas creates a hierarchy for the purpose of routing by adding another route parameter, area to controller and action. Esta seção aborda como o roteamento interage com as áreas. Consulte Áreas para obter detalhes sobre como as áreas são usadas com exibições.This section will discuss how routing interacts with areas - see Areas for details about how areas are used with views.

O exemplo a seguir configura o MVC para usar a rota convencional padrão e uma rota de área para uma área chamada Blog:The following example configures MVC to use the default conventional route and an area route for an area named Blog:

app.UseEndpoints(endpoints =>
{
    endpoints.MapAreaControllerRoute("blog_route", "Blog",
        "Manage/{controller}/{action}/{id?}");
    endpoints.MapControllerRoute("default_route", "{controller}/{action}/{id?}");
});

Ao fazer a correspondência de um caminho de URL como /Manage/Users/AddUser, a primeira rota produzirá os valores de rota { area = Blog, controller = Users, action = AddUser }.When matching a URL path like /Manage/Users/AddUser, the first route will produce the route values { area = Blog, controller = Users, action = AddUser }. O valor de rota area é produzido por um valor padrão para area. De fato, a rota criada por MapAreaRoute é equivalente à seguinte:The area route value is produced by a default value for area, in fact the route created by MapAreaRoute is equivalent to the following:

MapAreaRoute cria uma rota usando um valor padrão e a restrição para area usando o nome da área fornecido, nesse caso, Blog.MapAreaRoute creates a route using both a default value and constraint for area using the provided area name, in this case Blog. O valor padrão garante que a rota sempre produza { area = Blog, ... }, a restrição requer o valor { area = Blog, ... } para geração de URL.The default value ensures that the route always produces { area = Blog, ... }, the constraint requires the value { area = Blog, ... } for URL generation.

Dica

O roteamento convencional é dependente da ordem.Conventional routing is order-dependent. De modo geral, rotas com áreas devem ser colocadas mais no início na tabela de rotas, uma vez que são mais específicas que rotas sem uma área.In general, routes with areas should be placed earlier in the route table as they're more specific than routes without an area.

Usando o exemplo acima, os valores de rota corresponderiam à ação a seguir:Using the above example, the route values would match the following action:

using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}

O AreaAttribute é o que indica que um controlador faz parte de uma área; dizemos que esse controlador está na área Blog.The AreaAttribute is what denotes a controller as part of an area, we say that this controller is in the Blog area. Controladores sem um atributo [Area] não são membros de nenhuma área e não corresponderão quando o valor de rota area for fornecido pelo roteamento.Controllers without an [Area] attribute are not members of any area, and will not match when the area route value is provided by routing. No exemplo a seguir, somente o primeiro controlador listado pode corresponder aos valores de rota { area = Blog, controller = Users, action = AddUser }.In the following example, only the first controller listed can match the route values { area = Blog, controller = Users, action = AddUser }.

using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace1
{
    [Area("Blog")]
    public class UsersController : Controller
    {
        // GET /manage/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace2
{
    // Matches { area = Zebra, controller = Users, action = AddUser }
    [Area("Zebra")]
    public class UsersController : Controller
    {
        // GET /zebra/users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }        
    }
}
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace3
{
    // Matches { area = string.Empty, controller = Users, action = AddUser }
    // Matches { area = null, controller = Users, action = AddUser }
    // Matches { controller = Users, action = AddUser }
    public class UsersController : Controller
    {
        // GET /users/adduser
        public IActionResult AddUser()
        {
            var area = ControllerContext.ActionDescriptor.RouteValues["area"];
            var actionName = ControllerContext.ActionDescriptor.ActionName;
            var controllerName = ControllerContext.ActionDescriptor.ControllerName;

            return Content($"area name:{area}" +
                $" controller:{controllerName}  action name: {actionName}");
        }
    }
}

Observação

O namespace de cada controlador é mostrado aqui para fins de integridade – caso contrário, os controladores teriam um conflito de nomenclatura e gerariam um erro do compilador.The namespace of each controller is shown here for completeness - otherwise the controllers would have a naming conflict and generate a compiler error. Namespaces de classe não têm efeito sobre o roteamento do MVC.Class namespaces have no effect on MVC's routing.

Os primeiros dois controladores são membros de áreas e correspondem somente quando seus respectivos nomes de área são fornecidos pelo valor de rota area.The first two controllers are members of areas, and only match when their respective area name is provided by the area route value. O terceiro controlador não é um membro de nenhuma área e só pode corresponder quando nenhum valor para area for fornecido pelo roteamento.The third controller isn't a member of any area, and can only match when no value for area is provided by routing.

Observação

Em termos de não corresponder a nenhum valor, a ausência do valor de area é equivalente ao valor de area ser nulo ou uma cadeia de caracteres vazia.In terms of matching no value, the absence of the area value is the same as if the value for area were null or the empty string.

Ao executar uma ação dentro de uma área, o valor de rota para area estará disponível como um valor de ambiente para o roteamento usar para geração de URL.When executing an action inside an area, the route value for area will be available as an ambient value for routing to use for URL generation. Isso significa que, por padrão, as áreas atuam como se fossem autoadesivas para a geração de URL, como demonstrado no exemplo a seguir.This means that by default areas act sticky for URL generation as demonstrated by the following sample.

using Microsoft.AspNetCore.Mvc;

namespace MyApp.Namespace4
{
    [Area("Duck")]
    public class UsersController : Controller
    {
        // GET /Manage/users/GenerateURLInArea
        public IActionResult GenerateURLInArea()
        {
            // Uses the 'ambient' value of area.
            var url = Url.Action("Index", "Home");
            // Returns /Manage/Home/Index
            return Content(url);
        }

        // GET /Manage/users/GenerateURLOutsideOfArea
        public IActionResult GenerateURLOutsideOfArea()
        {
            // Uses the empty value for area.
            var url = Url.Action("Index", "Home", new { area = "" });
            // Returns /Manage
            return Content(url);
        }
    }
}

Entendendo IActionConstraintUnderstanding IActionConstraint

Observação

Esta seção é uma análise aprofundada dos elementos internos da estrutura e de como o MVC escolhe uma ação para ser executada.This section is a deep-dive on framework internals and how MVC chooses an action to execute. Um aplicativo típico não precisará de um IActionConstraint personalizadoA typical application won't need a custom IActionConstraint

Provavelmente, você já usou IActionConstraint mesmo que não esteja familiarizado com a interface.You have likely already used IActionConstraint even if you're not familiar with the interface. O atributo [HttpGet] e atributos [Http-VERB] semelhantes implementam IActionConstraint para limitar a execução de um método de ação.The [HttpGet] Attribute and similar [Http-VERB] attributes implement IActionConstraint in order to limit the execution of an action method.

public class ProductsController : Controller
{
    [HttpGet]
    public IActionResult Edit() { }

    public IActionResult Edit(...) { }
}

Presumindo a rota convencional padrão, o caminho de URL /Products/Edit produziria os valores { controller = Products, action = Edit }, que corresponderiam a ambas as ações mostradas aqui.Assuming the default conventional route, the URL path /Products/Edit would produce the values { controller = Products, action = Edit }, which would match both of the actions shown here. Na terminologia IActionConstraint, diríamos que essas duas ações são consideradas candidatas – uma vez que ambas correspondem aos dados da rota.In IActionConstraint terminology we would say that both of these actions are considered candidates - as they both match the route data.

Quando for executado, HttpGetAttribute indicará que Edit() corresponde a GET e não corresponde a nenhum outro verbo HTTP.When the HttpGetAttribute executes, it will say that Edit() is a match for GET and isn't a match for any other HTTP verb. A ação Edit(...) não tem restrições definidas e, portanto, corresponderá a qualquer verbo HTTP.The Edit(...) action doesn't have any constraints defined, and so will match any HTTP verb. Sendo assim, supondo um POST, Edit(...) será correspondente.So assuming a POST - only Edit(...) matches. Mas, para um GET, ambas as ações ainda podem corresponder – no entanto, uma ação com um IActionConstraint sempre é considerada melhor que uma ação sem.But, for a GET both actions can still match - however, an action with an IActionConstraint is always considered better than an action without. Assim, como Edit() tem [HttpGet], ela é considerada mais específica e será selecionada se as duas ações puderem corresponder.So because Edit() has [HttpGet] it's considered more specific, and will be selected if both actions can match.

Conceitualmente, IActionConstraint é uma forma de sobrecarga, mas em vez de uma sobrecarga de métodos com o mesmo nome, trata-se da sobrecarga entre ações que correspondem à mesma URL.Conceptually, IActionConstraint is a form of overloading, but instead of overloading methods with the same name, it's overloading between actions that match the same URL. O roteamento de atributo também usa IActionConstraint e pode fazer com que ações de controladores diferentes sejam consideradas candidatas.Attribute routing also uses IActionConstraint and can result in actions from different controllers both being considered candidates.

Implementando IActionConstraintImplementing IActionConstraint

A maneira mais simples de implementar um IActionConstraint é criar uma classe derivada de System.Attribute e colocá-la em suas ações e controladores.The simplest way to implement an IActionConstraint is to create a class derived from System.Attribute and place it on your actions and controllers. O MVC descobrirá automaticamente qualquer IActionConstraint que for aplicado como atributo.MVC will automatically discover any IActionConstraint that are applied as attributes. Você pode usar o modelo de aplicativo para aplicar restrições e, provavelmente, essa é a abordagem mais flexível, pois permite a você faça uma metaprogramação de como elas são aplicadas.You can use the application model to apply constraints, and this is probably the most flexible approach as it allows you to metaprogram how they're applied.

No exemplo a seguir, uma restrição escolhe uma ação com base em um código de país dos dados de rota.In the following example, a constraint chooses an action based on a country code from the route data. O exemplo completo no GitHub.The full sample on GitHub.

public class CountrySpecificAttribute : Attribute, IActionConstraint
{
    private readonly string _countryCode;

    public CountrySpecificAttribute(string countryCode)
    {
        _countryCode = countryCode;
    }

    public int Order
    {
        get
        {
            return 0;
        }
    }

    public bool Accept(ActionConstraintContext context)
    {
        return string.Equals(
            context.RouteContext.RouteData.Values["country"].ToString(),
            _countryCode,
            StringComparison.OrdinalIgnoreCase);
    }
}

Você é responsável por implementar o método Accept e por escolher uma "ordem" na qual a restrição deve ser executada.You are responsible for implementing the Accept method and choosing an 'Order' for the constraint to execute. Nesse caso, o método Accept retorna true para indicar que a ação é correspondente quando o valor de rota country é correspondente.In this case, the Accept method returns true to denote the action is a match when the country route value matches. Isso é diferente de um RouteValueAttribute, pois permite o fallback para uma ação não atribuída.This is different from a RouteValueAttribute in that it allows fallback to a non-attributed action. O exemplo mostra que se você definir uma ação en-US, um código de país como fr-FR fará o fallback para um controlador mais genérico que não tem [CountrySpecific(...)] aplicado.The sample shows that if you define an en-US action then a country code like fr-FR will fall back to a more generic controller that doesn't have [CountrySpecific(...)] applied.

A propriedade Order decide de qual estágio a restrição faz parte.The Order property decides which stage the constraint is part of. Restrições de ação são executadas em grupos com base no Order.Action constraints run in groups based on the Order. Por exemplo, todos atributos de método HTTP fornecidos pela estrutura usam o mesmo valor de Order para que sejam executados no mesmo estágio.For example, all of the framework provided HTTP method attributes use the same Order value so that they run in the same stage. Você pode ter tantos estágios quantos forem necessários para implementar suas políticas desejadas.You can have as many stages as you need to implement your desired policies.

Dica

Para decidir o valor para Order, considere se sua restrição deve ou não deve ser aplicada antes de métodos HTTP.To decide on a value for Order think about whether or not your constraint should be applied before HTTP methods. Números inferiores são executados primeiro.Lower numbers run first.