Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. 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 certas 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 Fornecedores (IApplicationModelProvider)
O modelo de aplicativo MVC ASP.NET Core inclui interfaces abstratas e classes de implementação concretas que descrevem um aplicativo MVC. Este modelo é o resultado de MVC descobrir os controladores, ações, parâmetros de ação, rotas e filtros do aplicativo 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 MVC padrão. Os parâmetros, nomes, rotas e filtros são usados como dados de configuração para ações e controladores.
O ASP.NET Core MVC Application Model tem a seguinte estrutura:
- Modelo de Aplicação
- 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 os níveis inferiores podem acessar e substituir valores de propriedade definidos por níveis mais altos na hierarquia. As propriedades são persistidas no ActionDescriptor.Properties quando as ações são criadas. Em seguida, quando uma solicitação está sendo tratada, todas as propriedades adicionadas ou modificadas por uma convenção podem ser acessadas através do ActionContext.ActionDescriptor. Usar propriedades é uma ótima maneira de configurar filtros, fichários de modelo e outros aspetos 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 padrão de provedor é um assunto avançado, principalmente para uso de frameworks. A maioria dos aplicativos deve usar convenções, não o padrão de provedor.
As implementações da interface IApplicationModelProvider "encapsulam" umas às outras, onde cada implementação chama OnProvidersExecuting em ordem crescente com base na sua propriedade Order. O OnProvidersExecuted método é então chamado em ordem inversa. O quadro define vários fornecedores:
Primeiro (Order=-1000):
DefaultApplicationModelProvider
Em seguida, (Order=-990):
AuthorizationApplicationModelProviderCorsApplicationModelProvider
Observação
A ordem na qual dois provedores com o mesmo valor para Order são chamados é indefinida e não deve ser confiada.
Observação
IApplicationModelProvider é um conceito avançado para os autores do framework ampliarem. Em geral, os aplicativos devem usar convenções e as estruturas devem usar provedores. A principal distinção é que os prestadores funcionam sempre antes das convenções.
O DefaultApplicationModelProvider estabelece muitos dos comportamentos padrão usados pelo ASP.NET MVC principal. As 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 do método de ação ao contexto
- Aplicação de rota e outros atributos
Alguns comportamentos internos são implementados pelo DefaultApplicationModelProvider. Este provedor é responsável pela construção do ControllerModel, que por sua vez referencia as instâncias de 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 Autorização simples no ASP.NET Core.
O CorsApplicationModelProvider implementa o comportamento associado a IEnableCorsAttribute e IDisableCorsAttribute. Para obter mais informações, consulte Habilitar solicitações entre origens (CORS) 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 da API .NET. No entanto, os provedores podem ser inspecionados na fonte de referência ASP.NET Core (repositório GitHub dotnet/aspnetcore). Use a pesquisa do GitHub para encontrar os fornecedores por nome e selecione a versão do código-fonte com a lista suspensa Mudar ramos/tags.
Convenções
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 sobrepor o modelo ou provedor inteiro. 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 personalizações dinamicamente. 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.
Estão disponíveis as seguintes convenções:
- IApplicationModelConvention
- IControllerModelConvention
- IActionModelConvention
- IParameterModelConvention
As convenções são aplicadas adicionando-as às opções MVC ou implementando atributos e aplicando-os a controladores, ações ou parâmetros de ação (semelhantes a filtros). Ao contrário dos filtros, as convenções só são executadas quando o aplicativo é iniciado, não como parte de cada solicitação.
Observação
Para obter informações sobre Razor as convenções de rota do Pages e do provedor de modelo de aplicativo, consulte Razor Rotas de páginas e convenções de aplicativo no ASP.NET Core.
Modifique 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 da coleção ActionDescriptor.Properties 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 do controlador também pode incluir propriedades personalizadas. As propriedades personalizadas substituem as propriedades existentes com o mesmo nome especificado no modelo de aplicativo. O seguinte atributo de convenção 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;
}
}
}
Esta 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 descrição ActionModel
Uma convenção de atributos separada pode ser aplicada a ações individuais, substituindo o comportamento já aplicado no nível do aplicativo ou 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 ela 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"];
}
}
Modifique o ParameterModel
A convenção a seguir pode ser aplicada aos parâmetros de ação para modificar seu BindingInfo. A convenção a seguir requer que o parâmetro seja um parâmetro de rota. Outras possíveis fontes de ligação, 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 em Startup.ConfigureServices:
options.Conventions.Add(new MustBeInRouteParameterModelConvention());
Modificar o ActionModel nome
A convenção a seguir modifica o ActionModel para atualizar o nome da ação à qual ele é aplicado. O novo nome é fornecido como um parâmetro para o atributo. Esse novo nome é usado pelo roteamento, portanto, 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;
}
}
}
Este atributo é aplicado a um método de ação no HomeController:
// Route: /Home/MyCoolAction
[CustomActionName("MyCoolAction")]
public string SomeName()
{
return ControllerContext.ActionDescriptor.ActionName;
}
Embora 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. Assim, o caminho utilizado para chegar a esta ação é /Home/MyCoolAction.
Observação
Este exemplo nesta seção é essencialmente o mesmo que usar o built-in ActionNameAttribute.
Convenção de roteamento personalizada
Use um IApplicationModelConvention para personalizar como o roteamento funciona. Por exemplo, a convenção a seguir incorpora namespaces de 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 é acrescentada como 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());
});
}
Sugestão
Adicione configurações ao middleware via MvcOptions usando a seguinte abordagem. O placeholder {CONVENTION} é a convenção para adicionar:
services.Configure<MvcOptions>(c => c.Conventions.Add({CONVENTION}));
O exemplo a seguir aplica uma convenção a rotas que não estão usando roteamento de atributo onde 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.";
}
}
}
Utilização do modelo de aplicação em WebApiCompatShim
ASP.NET Core MVC usa um conjunto diferente de convenções de ASP.NET Web API 2. Usando convenções personalizadas, você pode modificar o comportamento de um aplicativo MVC ASP.NET Core 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 certos atributos aplicados a eles. 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 mapearia para HttpGet). Ele só se aplica a ações que não usam roteamento de atributos.
Sobrecarga
UseWebApiOverloadingAttribute é utilizado para aplicar a WebApiOverloadingApplicationModelConvention convenção. Esta convenção acrescenta um OverloadActionConstraint ao processo de seleção de ações, 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âmetros
UseWebApiParameterConventionsAttribute é utilizado para aplicar a convenção de WebApiParameterConventionsApplicationModelConvention ação. Essa convenção especifica que os tipos simples usados como parâmetros de ação são vinculados do URI por padrão, enquanto os tipos complexos são vinculados do corpo da solicitação.
Rotas
UseWebApiRoutesAttribute controla se a convenção do controlador WebApiApplicationModelConvention é 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 da Web. Isso permite que seus controladores de API da Web escritos para API da Web e herdados dela ApiController funcionem durante a execução no MVC ASP.NET Core. Todos os UseWebApi* atributos listados anteriormente são aplicados à classe de controlador base. O ApiController expõe propriedades, métodos e tipos de resultados que são compatíveis com aqueles encontrados na API da Web.
Utilizar ApiExplorer para documentar uma aplicação
O modelo de aplicação expõe uma propriedade ApiExplorerModel em cada nível que pode ser usada para navegar na estrutura da aplicação. Isso pode ser usado para gerar páginas de ajuda para APIs da Web usando ferramentas como 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 esta 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 é habilitada ou desabilitada em qualquer nível dentro de um aplicativo.