Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Por Steve Smith
ASP.NET Core MVC define um modelo de aplicativo que representa os componentes de um aplicativo MVC. Leia e manipule este modelo para modificar como os elementos MVC se comportam. Por padrão, o MVC segue determinadas convenções para determinar quais classes são consideradas controladores, quais métodos nessas classes são ações e como os parâmetros e o roteamento se comportam. Personalize esse comportamento para atender às necessidades de um aplicativo criando convenções personalizadas e aplicando-as globalmente ou como atributos.
Modelos e provedores (IApplicationModelProvider)
O ASP.NET modelo de aplicativo Core MVC inclui interfaces abstratas e classes de implementação concretas que descrevem um aplicativo MVC. Esse modelo é o resultado da descoberta de controladores, ações, parâmetros de ação, rotas e filtros do MVC de acordo com as convenções padrão. Ao trabalhar com o modelo de aplicativo, modifique um aplicativo para seguir convenções diferentes do comportamento padrão do MVC. Os parâmetros, nomes, rotas e filtros são todos usados como dados de configuração para ações e controladores.
O modelo de aplicativo MVC do ASP.NET Core tem a seguinte estrutura:
- ApplicationModel
- Controladores (ControllerModel)
- Ações (ActionModel)
- Parâmetros (ParameterModel)
- Ações (ActionModel)
- Controladores (ControllerModel)
Cada nível do modelo tem acesso a uma coleção comum Properties , e níveis inferiores podem acessar e substituir valores de propriedade definidos por níveis mais altos na hierarquia. As propriedades são mantidas no ActionDescriptor.Properties momento em que as ações são criadas. Em seguida, quando uma solicitação está sendo tratada, quaisquer propriedades adicionadas ou modificadas por uma convenção podem ser acessadas por meio de ActionContext.ActionDescriptor. Usar propriedades é uma ótima maneira de configurar filtros, associadores de modelo e outros aspectos do modelo de aplicativo por ação.
Observação
A ActionDescriptor.Properties coleção não é thread safe (para gravações) após a inicialização do aplicativo. As convenções são a melhor maneira de adicionar dados com segurança a essa coleção.
ASP.NET Core MVC carrega o modelo de aplicativo usando um padrão de provedor, definido pela IApplicationModelProvider interface. Esta seção aborda alguns dos detalhes de implementação interna de como esse provedor funciona. O uso do "provider pattern" é um assunto avançado, principalmente para uso em frameworks. A maioria dos aplicativos deve usar convenções, não o padrão do provedor.
Implementações da IApplicationModelProvider interface "encapsulam" umas às outras, em que cada implementação chama OnProvidersExecuting em ordem crescente com base em sua Order propriedade. Em seguida, o OnProvidersExecuted método é chamado em ordem inversa. A estrutura define vários provedores:
Primeiro (Order=-1000):
DefaultApplicationModelProvider
Em seguida (Order=-990):
AuthorizationApplicationModelProviderCorsApplicationModelProvider
Observação
A ordem na qual dois provedores com o mesmo valor Order são chamados é indefinida e não deve ser confiada.
Observação
IApplicationModelProvider é um conceito avançado para extensões feitas por autores de framework. Em geral, os aplicativos devem usar convenções e as estruturas devem usar provedores. A principal distinção é que os provedores sempre são executados antes das convenções.
O DefaultApplicationModelProvider estabelece muitos dos comportamentos padrão usados por ASP.NET Core MVC. Suas responsabilidades incluem:
- Adicionando filtros globais ao contexto
- Adicionando controladores ao contexto
- Adicionando métodos de controlador público como ações
- Adicionando parâmetros de método de ação ao contexto
- Aplicando roteamento e outros atributos
Alguns comportamentos internos são implementados pelo DefaultApplicationModelProvider. Esse provedor é responsável pela construção da ControllerModel, que por sua vez faz referência às instâncias ActionModel, PropertyModel e ParameterModel. A DefaultApplicationModelProvider classe é um detalhe de implementação da estrutura interna que pode mudar no futuro.
O AuthorizationApplicationModelProvider é responsável por aplicar o comportamento associado aos atributos AuthorizeFilter e AllowAnonymousFilter. Para obter mais informações, consulte a autorização simples no ASP.NET Core.
O CorsApplicationModelProvider implementa o comportamento associado a IEnableCorsAttribute e IDisableCorsAttribute. Para obter mais informações, consulte Habilitar CORS (Solicitações entre Origens) no ASP.NET Core.
As informações sobre os provedores internos da estrutura descritas nesta seção não estão disponíveis por meio do navegador de API do .NET. No entanto, os provedores podem ser inspecionados na referência de código-fonte do ASP.NET Core (repositório GitHub do dotnet/aspnetcore). Use a pesquisa do GitHub para localizar os provedores pelo nome e selecione a versão da origem com a lista suspensa Branches/marcas do Switch .
Conventions
O modelo de aplicação define abstrações de convenção que fornecem uma maneira mais simples de personalizar o comportamento dos modelos do que substituir o modelo inteiro ou o provedor. Essas abstrações são a maneira recomendada de modificar o comportamento de um aplicativo. As convenções fornecem uma maneira de escrever código que aplica dinamicamente personalizações. Embora os filtros forneçam um meio de modificar o comportamento da estrutura, as personalizações permitem o controle sobre como todo o aplicativo funciona em conjunto.
As seguintes convenções estão disponíveis:
- IApplicationModelConvention
- IControllerModelConvention
- IActionModelConvention
- IParameterModelConvention
As convenções são aplicadas adicionando-as às opções do MVC ou implementando atributos e aplicando-as a controladores, ações ou parâmetros de ação (semelhante a filtros). Ao contrário dos filtros, as convenções só são executadas quando o aplicativo está sendo iniciado, não como parte de cada solicitação.
Observação
Para obter informações sobre Razor as convenções de provedor de modelo de aplicativo e de rota de Páginas, consulte Razor as convenções de rota e de aplicativo do Pages no ASP.NET Core.
Modificar o ApplicationModel
A convenção a seguir é usada para adicionar uma propriedade ao modelo de aplicativo:
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class ApplicationDescription : IApplicationModelConvention
{
private readonly string _description;
public ApplicationDescription(string description)
{
_description = description;
}
public void Apply(ApplicationModel application)
{
application.Properties["description"] = _description;
}
}
}
As convenções de modelo de aplicativo são aplicadas como opções quando o MVC é adicionado em Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("My Application Description"));
options.Conventions.Add(new NamespaceRoutingConvention());
});
}
As propriedades são acessíveis a partir da ActionDescriptor.Properties coleção nas ações do controlador.
public class AppModelController : Controller
{
public string Description()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
}
Modificar a descrição ControllerModel
O modelo de controlador também pode incluir propriedades personalizadas. As propriedades personalizadas substituem as propriedades existentes com o mesmo nome especificado no modelo de aplicativo. O atributo de convenção a seguir adiciona uma descrição no nível do controlador:
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class ControllerDescriptionAttribute : Attribute, IControllerModelConvention
{
private readonly string _description;
public ControllerDescriptionAttribute(string description)
{
_description = description;
}
public void Apply(ControllerModel controllerModel)
{
controllerModel.Properties["description"] = _description;
}
}
}
Essa convenção é aplicada como um atributo em um controlador:
[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
public string Index()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
Modificar a ActionModel descrição
Uma convenção de atributo separada pode ser aplicada a ações individuais, substituindo o comportamento já aplicado no nível do aplicativo ou do controlador:
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class ActionDescriptionAttribute : Attribute, IActionModelConvention
{
private readonly string _description;
public ActionDescriptionAttribute(string description)
{
_description = description;
}
public void Apply(ActionModel actionModel)
{
actionModel.Properties["description"] = _description;
}
}
}
Aplicar isso a uma ação dentro do controlador demonstra como ele substitui a convenção no nível do controlador:
[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
public string Index()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
[ActionDescription("Action Description")]
public string UseActionDescriptionAttribute()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
}
Modificar o ParameterModel
A convenção a seguir pode ser aplicada a parâmetros de ação para modificar seus BindingInfo. A convenção a seguir exige que o parâmetro seja um parâmetro de rota. Outras fontes de associação potenciais, como valores de cadeia de caracteres de consulta, são ignoradas:
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace AppModelSample.Conventions
{
public class MustBeInRouteParameterModelConvention : Attribute, IParameterModelConvention
{
public void Apply(ParameterModel model)
{
if (model.BindingInfo == null)
{
model.BindingInfo = new BindingInfo();
}
model.BindingInfo.BindingSource = BindingSource.Path;
}
}
}
O atributo pode ser aplicado a qualquer parâmetro de ação:
public class ParameterModelController : Controller
{
// Will bind: /ParameterModel/GetById/123
// WON'T bind: /ParameterModel/GetById?id=123
public string GetById([MustBeInRouteParameterModelConvention]int id)
{
return $"Bound to id: {id}";
}
}
Para aplicar a convenção a todos os parâmetros de ação, adicione o MustBeInRouteParameterModelConvention a MvcOptions: Startup.ConfigureServices
options.Conventions.Add(new MustBeInRouteParameterModelConvention());
Modificar o ActionModel nome
A convenção a seguir modifica o ActionModelnome da ação à qual ela é aplicada. O novo nome é fornecido como um parâmetro para o atributo. Esse novo nome é usado pelo roteamento, portanto, ele afeta a rota usada para alcançar esse método de ação:
using System;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class CustomActionNameAttribute : Attribute, IActionModelConvention
{
private readonly string _actionName;
public CustomActionNameAttribute(string actionName)
{
_actionName = actionName;
}
public void Apply(ActionModel actionModel)
{
// this name will be used by routing
actionModel.ActionName = _actionName;
}
}
}
Esse atributo é aplicado a um método de ação no HomeController:
// Route: /Home/MyCoolAction
[CustomActionName("MyCoolAction")]
public string SomeName()
{
return ControllerContext.ActionDescriptor.ActionName;
}
Mesmo que o nome do método seja SomeName, o atributo substitui a convenção MVC de usar o nome do método e substitui o nome da ação por MyCoolAction. Portanto, a rota usada para chegar a essa ação é /Home/MyCoolAction.
Observação
Este exemplo nesta seção é essencialmente igual a usar o integrado ActionNameAttribute.
Convenção de roteamento personalizado
Use um IApplicationModelConvention para personalizar como o roteamento funciona. Por exemplo, a convenção a seguir incorpora os namespaces dos controladores em suas rotas, substituindo . no namespace por / na rota.
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using System.Linq;
namespace AppModelSample.Conventions
{
public class NamespaceRoutingConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
foreach (var controller in application.Controllers)
{
var hasAttributeRouteModels = controller.Selectors
.Any(selector => selector.AttributeRouteModel != null);
if (!hasAttributeRouteModels
&& controller.ControllerName.Contains("Namespace")) // affect one controller in this sample
{
// Replace the . in the namespace with a / to create the attribute route
// Ex: MySite.Admin namespace will correspond to MySite/Admin attribute route
// Then attach [controller], [action] and optional {id?} token.
// [Controller] and [action] is replaced with the controller and action
// name to generate the final template
controller.Selectors[0].AttributeRouteModel = new AttributeRouteModel()
{
Template = controller.ControllerType.Namespace.Replace('.', '/') + "/[controller]/[action]/{id?}"
};
}
}
// You can continue to put attribute route templates for the controller actions depending on the way you want them to behave
}
}
}
A convenção é adicionada como uma opção em Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("My Application Description"));
options.Conventions.Add(new NamespaceRoutingConvention());
});
}
Dica
Adicione convenções ao middlewareMvcOptions usando a abordagem a seguir. O {CONVENTION} placeholder é a convenção a ser adicionada:
services.Configure<MvcOptions>(c => c.Conventions.Add({CONVENTION}));
O exemplo a seguir aplica uma convenção a rotas que não estão usando o roteamento de atributo em que o controlador tem Namespace em seu nome:
using Microsoft.AspNetCore.Mvc;
namespace AppModelSample.Controllers
{
public class NamespaceRoutingController : Controller
{
// using NamespaceRoutingConvention
// route: /AppModelSample/Controllers/NamespaceRouting/Index
public string Index()
{
return "This demonstrates namespace routing.";
}
}
}
Uso do modelo de aplicativo em WebApiCompatShim
ASP.NET Core MVC usa um conjunto diferente de convenções de ASP.NET API Web 2. Usando convenções personalizadas, você pode modificar o comportamento de um aplicativo ASP.NET Core MVC para ser consistente com o de um aplicativo de API Web. A Microsoft envia o WebApiCompatShim pacote NuGet especificamente para essa finalidade.
Observação
Para obter mais informações sobre a migração de ASP.NET API Web, consulte Migrar de ASP.NET API Web para ASP.NET Core.
Para usar o shim de compatibilidade da API Web:
- Adicione o
Microsoft.AspNetCore.Mvc.WebApiCompatShimpacote ao projeto. - Adicione as convenções ao MVC chamando AddWebApiConventions
Startup.ConfigureServices:
services.AddMvc().AddWebApiConventions();
As convenções fornecidas pelo shim são aplicadas apenas a partes do aplicativo que tiveram determinados atributos aplicados a elas. Os quatro atributos a seguir são usados para controlar quais controladores devem ter suas convenções modificadas pelas convenções do shim:
- UseWebApiActionConventionsAttribute
- UseWebApiOverloadingAttribute
- UseWebApiParameterConventionsAttribute
- UseWebApiRoutesAttribute
Convenções de ação
UseWebApiActionConventionsAttribute é usado para mapear o método HTTP para ações com base em seu nome (por exemplo, Get seria mapeado para HttpGet). Ele só se aplica a ações que não usam roteamento de atributo.
Sobrecarga
UseWebApiOverloadingAttribute é usado para aplicar a WebApiOverloadingApplicationModelConvention convenção. Essa convenção adiciona um OverloadActionConstraint ao processo de seleção de ação, que limita as ações candidatas àquelas para as quais a solicitação satisfaz todos os parâmetros não opcionais.
Convenções de parâmetro
UseWebApiParameterConventionsAttribute é usado para aplicar a convenção de ação WebApiParameterConventionsApplicationModelConvention. Essa convenção especifica que tipos simples usados como parâmetros de ação são associados do URI por padrão, enquanto tipos complexos são associados do corpo da solicitação.
Routes
UseWebApiRoutesAttribute controla se a convenção do WebApiApplicationModelConvention controlador é aplicada. Quando habilitada, essa convenção é usada para adicionar suporte para áreas à rota e indica que o controlador está na api área.
Além de um conjunto de convenções, o pacote de compatibilidade inclui uma System.Web.Http.ApiController classe base que substitui a fornecida pela API Web. Isso permite que os controladores de API Web, escritos para a API Web e que herdam de seu ApiController, funcionem ao serem executados no ASP.NET Core MVC. Todos os UseWebApi* atributos listados anteriormente são aplicados à classe de controlador base.
ApiController expõe propriedades, métodos e tipos de resultados que são compatíveis com os encontrados na API Web.
Usar ApiExplorer para documentar um aplicativo
O modelo de aplicativo expõe uma ApiExplorerModel propriedade em cada nível que pode ser usada para percorrer a estrutura do aplicativo. Isso pode ser usado para gerar páginas de ajuda para APIs Web usando ferramentas como o Swagger. A ApiExplorer propriedade expõe uma IsVisible propriedade que pode ser definida para especificar quais partes do modelo do aplicativo devem ser expostas. Defina essa configuração usando uma convenção:
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class EnableApiExplorerApplicationConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
application.ApiExplorer.IsVisible = true;
}
}
}
Usando essa abordagem (e convenções adicionais, se necessário), a visibilidade da API está habilitada ou desabilitada em qualquer nível dentro de um aplicativo.