Roteamento no ASP.NET Web API

por Mike Wasson

Este artigo descreve como ASP.NET Web API roteia as solicitações HTTP para os controladores.

Note

Se você estiver familiarizado com o ASP.NET MVC, o roteamento da API Web é muito semelhante ao roteamento do MVC. A principal diferença é que a API da Web usa o verbo HTTP, não o caminho do URI, para selecionar a ação. Você também pode usar o roteamento no estilo MVC na API da Web. Este artigo não assume nenhum conhecimento do ASP.NET MVC.

Tabelas de roteamento

No ASP.NET Web API, um controlador é uma classe que MANIPULA solicitações HTTP. Os métodos públicos do controlador são chamados de métodos de ação ou simplesmente ações. Quando a estrutura da API Web recebe uma solicitação, ela roteia a solicitação para uma ação.

Para determinar qual ação invocar, a estrutura usa uma tabela de roteamento. O modelo de projeto do Visual Studio para API da Web cria uma rota padrão:

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

Essa rota é definida no arquivo WebApiConfig.cs , que é colocado no diretório * _ inicial do aplicativo* :

Para obter mais informações sobre a WebApiConfig classe, consulte configurando ASP.NET Web API.

Se você hospedar a API Web de hospedagem própria, deverá definir a tabela de roteamento diretamente no HttpSelfHostConfiguration objeto. Para obter mais informações, consulte auto-hospedar uma API Web.

Cada entrada na tabela de roteamento contém um modelo de rota. O modelo de rota padrão para a API Web é " API/{Controller}/{ID} " . Neste modelo, " a API " é um segmento de caminho literal e {Controller} e {ID} são variáveis de espaço reservado.

Quando a estrutura da API Web recebe uma solicitação HTTP, ela tenta corresponder o URI em um dos modelos de rota na tabela de roteamento. Se nenhuma rota corresponder, o cliente receberá um erro 404. Por exemplo, os seguintes URIs correspondem à rota padrão:

  • /api/contacts
  • /api/contacts/1
  • /api/products/gizmo1

No entanto, o URI a seguir não corresponde, pois ele não tem o " segmento de API " :

  • /contacts/1

Note

O motivo para usar "API" na rota é evitar colisões com o roteamento MVC do ASP.NET. Dessa forma, você pode fazer com que " " o/Contacts vá para um controlador MVC e " /API/Contacts " vá para um controlador de API da Web. É claro que, se você não gostar dessa Convenção, poderá alterar a tabela de rotas padrão.

Quando uma rota correspondente é encontrada, a API da Web seleciona o controlador e a ação:

  • Para localizar o controlador, a API Web " adiciona " o controlador ao valor da variável {Controller} .
  • Para localizar a ação, a API Web examina o verbo HTTP e, em seguida, procura uma ação cujo nome começa com esse nome de verbo HTTP. Por exemplo, com uma solicitação GET, a API da Web procura uma ação prefixada com " Get " , como " GetContact " ou " GetAllContacts " . Essa convenção se aplica somente aos verbos de GET, POST, PUT, excluir, cabeçalho, opções e PATCH. Você pode habilitar outros verbos HTTP usando atributos em seu controlador. Veremos um exemplo disso mais tarde.
  • Outras variáveis de espaço reservado no modelo de rota, como {ID}, são mapeadas para parâmetros de ação.

Vejamos um exemplo. Suponha que você defina o controlador a seguir:

public class ProductsController : ApiController
{
    public IEnumerable<Product> GetAllProducts() { }
    public Product GetProductById(int id) { }
    public HttpResponseMessage DeleteProduct(int id){ }
}

Aqui estão algumas solicitações HTTP possíveis, juntamente com a ação que é invocada para cada uma:

Verbo HTTP Caminho do URI Ação Parâmetro
GET API/produtos GetAllProducts None
GET API/produtos/4 GetProductById 4
Delete (excluir) API/produtos/4 DeleteProduct 4
POST API/produtos (sem correspondência)

Observe que o segmento {ID} do URI, se presente, está mapeado para o parâmetro ID da ação. Neste exemplo, o controlador define dois métodos GET, um com um parâmetro de ID e outro sem parâmetros.

Além disso, observe que a solicitação POST falhará, porque o controlador não define um " método post.... "

Variações de roteamento

A seção anterior descreveu o mecanismo de roteamento básico para ASP.NET Web API. Esta seção descreve algumas variações.

Verbos HTTP

Em vez de usar a Convenção de nomenclatura para verbos HTTP, você pode especificar explicitamente o verbo HTTP para uma ação decorando o método de ação com um dos seguintes atributos:

  • [HttpGet]
  • [HttpPut]
  • [HttpPost]
  • [HttpDelete]
  • [HttpHead]
  • [HttpOptions]
  • [HttpPatch]

No exemplo a seguir, o FindProduct método é mapeado para solicitações GET:

public class ProductsController : ApiController
{
    [HttpGet]
    public Product FindProduct(id) {}
}

Para permitir vários verbos HTTP para uma ação ou para permitir verbos HTTP diferentes de GET, PUT, POST, DELETE, HEAD, OPTIONS e PATCH, use o [AcceptVerbs] atributo, que usa uma lista de VERBOS http.

public class ProductsController : ApiController
{
    [AcceptVerbs("GET", "HEAD")]
    public Product FindProduct(id) { }

    // WebDAV method
    [AcceptVerbs("MKCOL")]
    public void MakeCollection() { }
}

Roteamento por nome de ação

Com o modelo de roteamento padrão, a API da Web usa o verbo HTTP para selecionar a ação. No entanto, você também pode criar uma rota onde o nome da ação está incluído no URI:

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

Nesse modelo de rota, o parâmetro {Action} nomeia o método de ação no controlador. Com esse estilo de roteamento, use atributos para especificar os verbos HTTP permitidos. Por exemplo, suponha que o controlador tenha o seguinte método:

public class ProductsController : ApiController
{
    [HttpGet]
    public string Details(int id);
}

Nesse caso, uma solicitação GET para "API/produtos/detalhes/1" mapearia para o Details método. Esse estilo de roteamento é semelhante ao ASP.NET MVC e pode ser apropriado para uma API de estilo RPC.

Você pode substituir o nome da ação usando o [ActionName] atributo. No exemplo a seguir, há duas ações que são mapeadas para " API/Products/thumbnail/ID. Um é compatível com GET e o outro oferece suporte a POST:

public class ProductsController : ApiController
{
    [HttpGet]
    [ActionName("Thumbnail")]
    public HttpResponseMessage GetThumbnailImage(int id);

    [HttpPost]
    [ActionName("Thumbnail")]
    public void AddThumbnailImage(int id);
}

Não ações

Para impedir que um método seja invocado como uma ação, use o [NonAction] atributo. Isso sinaliza para a estrutura que o método não é uma ação, mesmo que, caso contrário, correspondam às regras de roteamento.

// Not an action method.
[NonAction]  
public string GetPrivateData() { ... }

Leitura Adicional

Este tópico forneceu uma exibição de alto nível do roteamento. Para obter mais detalhes, consulte seleção de roteamento e ação, que descreve exatamente como a estrutura corresponde a um URI para uma rota, seleciona um controlador e, em seguida, seleciona a ação a ser invocada.