Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Por Steve Smith
ASP.NET Core MVC define un modelo de aplicación que representa los componentes de una aplicación MVC. Lea y manipule este modelo para modificar el comportamiento de los elementos MVC. De forma predeterminada, MVC sigue ciertas convenciones para determinar qué clases se consideran controladores, qué métodos de esas clases son acciones y cómo se comportan los parámetros y el enrutamiento. Personalice este comportamiento para satisfacer las necesidades de una aplicación mediante la creación de convenciones personalizadas y su aplicación global o como atributos.
Modelos y proveedores (IApplicationModelProvider)
El modelo de aplicación ASP.NET Core MVC incluye interfaces abstractas y clases de implementación concretas que describen una aplicación MVC. Este modelo es el resultado de MVC que detecta los controladores, acciones, parámetros de acción, rutas y filtros de la aplicación según las convenciones predeterminadas. Al trabajar con el modelo de aplicación, modifique una aplicación para seguir convenciones diferentes del comportamiento predeterminado de MVC. Los parámetros, nombres, rutas y filtros se usan como datos de configuración para acciones y controladores.
El modelo de aplicación ASP.NET Core MVC tiene la siguiente estructura:
- ApplicationModel
- Controladores (ControllerModel)
- Acciones (Modelo de Acción)
- Parámetros (ParameterModel)
- Acciones (Modelo de Acción)
- Controladores (ControllerModel)
Cada nivel del modelo tiene acceso a una colección común Properties, y los niveles inferiores pueden acceder a los valores de propiedad establecidos por los niveles superiores y sobrescribirlos en la jerarquía. Las propiedades se conservan en ActionDescriptor.Properties cuando se crean las acciones. A continuación, cuando se maneja una solicitud, se puede acceder a las propiedades que una convención haya agregado o modificado a través de ActionContext.ActionDescriptor. El uso de propiedades es una excelente manera de configurar filtros, enlazadores de modelos y otros aspectos del modelo de aplicación por acción.
Nota:
La ActionDescriptor.Properties colección no es segura para subprocesos (para escrituras) después del inicio de la aplicación. Las convenciones son la mejor manera de agregar datos de forma segura a esta colección.
ASP.NET Core MVC carga el modelo de aplicación mediante un patrón de proveedor, definido por la IApplicationModelProvider interfaz . En esta sección se describen algunos de los detalles de implementación internos de cómo funciona este proveedor. El uso del patrón de proveedor es un tema avanzado, principalmente para el uso del marco. La mayoría de las aplicaciones deben usar convenciones, no el patrón de proveedor.
Las implementaciones de la IApplicationModelProvider interfaz "se envuelven" unas a otras, donde cada implementación llama a OnProvidersExecuting en orden ascendente en función de la propiedad Order. A continuación, se llama al método OnProvidersExecuted en orden inverso. El marco define varios proveedores:
Primero (Order=-1000):
DefaultApplicationModelProvider
A continuación (Order=-990):
AuthorizationApplicationModelProviderCorsApplicationModelProvider
Nota:
El orden en el que se llama a dos proveedores con el mismo valor para Order no está definido y no debe basarse en ellos.
Nota:
IApplicationModelProvider es un concepto avanzado para que los autores del marco amplíen. En general, las aplicaciones deben usar convenciones y los marcos deben usar proveedores. La distinción clave es que los proveedores de servicios siempre se ejecutan antes de las convenciones.
DefaultApplicationModelProvider establece muchos de los comportamientos predeterminados usados por ASP.NET Core MVC. Sus responsabilidades incluyen:
- Adición de filtros globales al contexto
- Adición de controladores al contexto
- Adición de métodos de controlador público como acciones
- Adición de parámetros del método de acción al contexto
- Aplicación de rutas y otros atributos
Algunos comportamientos integrados se implementan mediante .DefaultApplicationModelProvider Este proveedor es responsable de construir el ControllerModel, que a su vez hace referencia a las instancias de ActionModel, PropertyModel y ParameterModel. La DefaultApplicationModelProvider clase es un detalle de implementación del marco interno que puede cambiar en el futuro.
AuthorizationApplicationModelProvider es responsable de aplicar el comportamiento asociado a los AuthorizeFilter atributos y AllowAnonymousFilter . Para obtener más información, consulte Autorización sencilla en ASP.NET Core.
CorsApplicationModelProvider implementa el comportamiento asociado a IEnableCorsAttribute y IDisableCorsAttribute. Para obtener más información, vea Habilitar solicitudes entre orígenes (CORS) en ASP.NET Core.
La información sobre los proveedores internos del marco que se describe en esta sección no está disponible a través del explorador de API de .NET. Sin embargo, pueden inspeccionarse los proveedores en el código fuente de referencia de ASP.NET Core (repositorio de GitHub dotnet/aspnetcore). Utilice la búsqueda de GitHub para buscar los proveedores por nombre y seleccione la versión del origen con la lista desplegable Cambiar ramas/etiquetas.
Conventions
El modelo de aplicación define abstracciones de convención que proporcionan una manera más sencilla de personalizar el comportamiento de los modelos que sobrescribir todo el modelo o proveedor. Estas abstracciones son la manera recomendada de modificar el comportamiento de una aplicación. Las convenciones proporcionan una manera de escribir código que aplica dinámicamente las personalizaciones. Aunque los filtros proporcionan un medio para modificar el comportamiento del marco, las personalizaciones permiten controlar cómo funciona toda la aplicación conjuntamente.
Están disponibles las siguientes convenciones:
- IApplicationModelConvention
- IControllerModelConvention
- IActionModelConvention
- IParameterModelConvention
Las convenciones se aplican agregando a las opciones de MVC o implementando atributos y aplicándolos a controladores, acciones o parámetros de acción (similares a los filtros). A diferencia de los filtros, las convenciones solo se ejecutan cuando se inicia la aplicación, no como parte de cada solicitud.
Nota:
Para obtener información sobre las convenciones de ruta de Pages y proveedor de modelos de aplicación, consulte Razor las convenciones de ruta y aplicación de Pages en ASP.NET Core.
Modificar el ApplicationModel
La convención siguiente se usa para agregar una propiedad al modelo de aplicación:
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;
}
}
}
Las convenciones del modelo de aplicación se aplican como opciones cuando se agrega MVC en Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("My Application Description"));
options.Conventions.Add(new NamespaceRoutingConvention());
});
}
Las propiedades son accesibles desde la colección ActionDescriptor.Properties dentro de las acciones del controlador.
public class AppModelController : Controller
{
public string Description()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
}
Modificación de la ControllerModel descripción
El modelo de controlador también puede incluir propiedades personalizadas. Las propiedades personalizadas invalidan las propiedades existentes con el mismo nombre especificado en el modelo de aplicación. El atributo de convención siguiente agrega una descripción en el nivel de 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 convención se aplica como atributo en un controlador:
[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
public string Index()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
Modificación de la ActionModel descripción
Una convención de atributo independiente se puede aplicar a acciones individuales, reemplazando el comportamiento ya aplicado en el nivel de aplicación o 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;
}
}
}
Al aplicar esto a una acción dentro del controlador se muestra cómo invalida la convención de nivel de 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 el ParameterModel
La convención siguiente se puede aplicar a los parámetros de acción para modificar su BindingInfo. La convención siguiente requiere que el parámetro sea un parámetro de ruta. Otros posibles orígenes de enlace, como los valores de cadena de consulta, se omiten:
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;
}
}
}
El atributo se puede aplicar a cualquier parámetro de acción:
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 la convención a todos los parámetros de acción, agregue el MustBeInRouteParameterModelConvention a MvcOptions en Startup.ConfigureServices:
options.Conventions.Add(new MustBeInRouteParameterModelConvention());
Modificación del ActionModel nombre
La siguiente convención modifica el ActionModel para actualizar el nombre de la acción a la que se aplica. El nuevo nombre se proporciona como un parámetro para el atributo . Este nuevo nombre se usa mediante el enrutamiento, por lo que afecta a la ruta que se usa para alcanzar este método de acción:
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 se aplica a un método de acción en :HomeController
// Route: /Home/MyCoolAction
[CustomActionName("MyCoolAction")]
public string SomeName()
{
return ControllerContext.ActionDescriptor.ActionName;
}
Aunque el nombre del método es SomeName, el atributo invalida la convención de MVC de usar el nombre del método y reemplaza el nombre de la acción por MyCoolAction. Por lo tanto, la ruta utilizada para llegar a esta acción es /Home/MyCoolAction.
Nota:
Este ejemplo en esta sección es esencialmente el mismo que usar el integrado ActionNameAttribute.
Convención de enrutamiento personalizada
Usa un IApplicationModelConvention para personalizar cómo funciona el enrutamiento. Por ejemplo, la siguiente convención incorpora los namespaces de controladores a sus rutas, reemplazando . en el namespace por / en la ruta.
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
}
}
}
La convención se agrega como opción en Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("My Application Description"));
options.Conventions.Add(new NamespaceRoutingConvention());
});
}
Sugerencia
Agregue convenciones al middleware mediante MvcOptions usando el siguiente enfoque. El {CONVENTION} marcador de posición es la convención para agregar:
services.Configure<MvcOptions>(c => c.Conventions.Add({CONVENTION}));
En el ejemplo siguiente se aplica una convención a las rutas que no usan el enrutamiento de atributos donde el nombre del controlador contiene Namespace.
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 del modelo de aplicación en WebApiCompatShim
ASP.NET Core MVC usa un conjunto diferente de convenciones de ASP.NET Web API 2. Utilizando convenciones personalizadas, puede modificar el comportamiento de una aplicación ASP.NET Core MVC para que sea coherente con el de una aplicación de API web. Microsoft envía el WebApiCompatShim paquete NuGet específicamente para este propósito.
Nota:
Para obtener más información sobre la migración desde ASP.NET API web, consulte Migración de ASP.NET WEB API a ASP.NET Core.
Para usar el Shim de Compatibilidad de la API Web:
- Agregue el
Microsoft.AspNetCore.Mvc.WebApiCompatShimpaquete al proyecto. - Agregue las convenciones a MVC llamando a AddWebApiConventions en
Startup.ConfigureServices:
services.AddMvc().AddWebApiConventions();
Las convenciones proporcionadas por el shim de compatibilidad solo se aplican a las partes de la aplicación que tienen ciertos atributos aplicados a ellas. Los siguientes cuatro atributos se usan para determinar qué controladores deben tener sus convenciones modificadas por las convenciones del 'shim':
- UseWebApiActionConventionsAttribute
- UseWebApiOverloadingAttribute
- UseWebApiParameterConventionsAttribute
- UseWebApiRoutesAttribute
Convenciones de acción
UseWebApiActionConventionsAttribute se usa para asignar el método HTTP a las acciones en función de su nombre (por ejemplo, Get se asignaría a HttpGet). Solo se aplica a las acciones que no usan el enrutamiento de atributos.
Sobrecarga
UseWebApiOverloadingAttribute se usa para aplicar la WebApiOverloadingApplicationModelConvention convención. Esta convención agrega un OverloadActionConstraint al proceso de selección de acciones, que limita las acciones candidatas a aquellas para las cuales la solicitud satisface todos los parámetros no opcionales.
Convenciones de parámetro
UseWebApiParameterConventionsAttribute se usa para aplicar la convención de WebApiParameterConventionsApplicationModelConvention acción. Esta convención especifica que los tipos simples usados como parámetros de acción se enlazan desde el URI de forma predeterminada, mientras que los tipos complejos se enlazan desde el cuerpo de la solicitud.
Routes
UseWebApiRoutesAttribute controla si se aplica la convención del WebApiApplicationModelConvention controlador. Cuando está habilitada, esta convención se usa para agregar compatibilidad con áreas a la ruta e indica que el controlador está en el api área.
Además de un conjunto de convenciones, el paquete de compatibilidad incluye una System.Web.Http.ApiController clase base que reemplaza la proporcionada por la API web. Esto permite que los controladores de API web escritos para la API web y que heredan de su ApiController funcionen correctamente mientras se ejecutan en ASP.NET Core MVC. Todos los UseWebApi* atributos enumerados anteriormente se aplican a la clase de controlador base.
ApiController Expone propiedades, métodos y tipos de resultados que son compatibles con los que se encuentran en la API web.
Uso ApiExplorer para documentar una aplicación
El modelo de aplicación expone una ApiExplorerModel propiedad en cada nivel que se puede usar para recorrer la estructura de la aplicación. Esto se puede usar para generar páginas de ayuda para las API web mediante herramientas como Swagger. La ApiExplorer propiedad expone una IsVisible propiedad que se puede establecer para especificar qué partes del modelo de la aplicación se deben exponer. Configure esta opción mediante una convención:
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class EnableApiExplorerApplicationConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
application.ApiExplorer.IsVisible = true;
}
}
}
Con este enfoque (y convenciones adicionales si es necesario), la visibilidad de la API está habilitada o deshabilitada en cualquier nivel dentro de una aplicación.