Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Av Steve Smith
ASP.NET Core MVC definierar en programmodell som representerar komponenterna i en MVC-app. Läsa och ändra den här modellen för att ändra hur MVC-element beter sig. Som standard följer MVC vissa konventioner för att avgöra vilka klasser som betraktas som kontrollanter, vilka metoder i dessa klasser som är åtgärder och hur parametrar och routning fungerar. Anpassa det här beteendet efter en apps behov genom att skapa anpassade konventioner och tillämpa dem globalt eller som attribut.
Modeller och leverantörer (IApplicationModelProvider)
ASP.NET Core MVC-programmodellen innehåller både abstrakta gränssnitt och konkreta implementeringsklasser som beskriver ett MVC-program. Den här modellen är resultatet av att MVC identifierar appens kontrollanter, åtgärder, åtgärdsparametrar, vägar och filter enligt standardkonventionerna. Genom att arbeta med programmodellen ändrar du en app så att den följer olika konventioner från MVC-standardbeteendet. Parametrar, namn, vägar och filter används alla som konfigurationsdata för åtgärder och kontrollanter.
ASP.NET Core MVC-programmodellen har följande struktur:
- ApplicationModel
- Styrenheter (ControllerModel)
- Åtgärder (ActionModel)
- Parametrar (ParameterModel)
- Åtgärder (ActionModel)
- Styrenheter (ControllerModel)
Varje nivå i modellen har åtkomst till en gemensam Properties samling, och lägre nivåer kan komma åt och skriva över egenskapsvärden som anges av högre nivåer i hierarkin. Egenskaperna sparas i ActionDescriptor.Properties när åtgärderna skapas. När en begäran sedan hanteras kan alla egenskaper som en konvention har lagts till eller ändrat nås via ActionContext.ActionDescriptor. Att använda egenskaper är ett bra sätt att konfigurera filter, modellbindare och andra appmodellaspekter per åtgärd.
Anmärkning
Samlingen ActionDescriptor.Properties är inte trådsäker (för skrivningar) efter appstart. Konventioner är det bästa sättet att på ett säkert sätt lägga till data i den här samlingen.
ASP.NET Core MVC läser in programmodellen med hjälp av ett providermönster som definieras av IApplicationModelProvider gränssnittet. Det här avsnittet beskriver några av de interna implementeringsdetaljerna för hur den här providern fungerar. Användning av providermönstret är ett avancerat ämne, främst för ramverksanvändning. De flesta appar bör använda konventioner, inte providermönstret.
Implementeringar av IApplicationModelProvider-gränssnittet omsluter varandra, där varje implementering anropar OnProvidersExecuting i stigande ordning baserat på dess Order-egenskap. Metoden OnProvidersExecuted anropas sedan i omvänd ordning. Ramverket definierar flera leverantörer:
Först (Order=-1000):
DefaultApplicationModelProvider
Sedan (Order=-990):
AuthorizationApplicationModelProviderCorsApplicationModelProvider
Anmärkning
Den ordning i vilken två leverantörer med samma värde för Order anropas är odefinierad och bör inte åberopas.
Anmärkning
IApplicationModelProvider är ett avancerat begrepp för ramverksförfattare att utöka. I allmänhet bör appar använda konventioner och ramverk bör använda leverantörer. Den viktigaste skillnaden är att tjänster alltid körs före konventioner.
Etablerar DefaultApplicationModelProvider många av de standardbeteenden som används av ASP.NET Core MVC. Dess ansvarsområden omfattar:
- Lägga till globala filter i kontexten
- Lägga till kontrollanter i kontexten
- Lägga till publika kontrollermetoder som åtgärder
- Lägga till åtgärdsmetodparametrar i kontexten
- Tillämpa routning och andra attribut
Vissa inbyggda beteenden implementeras av DefaultApplicationModelProvider. Den här providern ansvarar för att konstruera ControllerModel, som i sin tur refererar till ActionModel, PropertyModel och ParameterModel-instanser. Klassen DefaultApplicationModelProvider är en intern ramverksimplementeringsdetalj som kan ändras i framtiden.
AuthorizationApplicationModelProvider Ansvarar för att tillämpa beteendet som är associerat med attributen AuthorizeFilter ochAllowAnonymousFilter. Mer information finns i Enkel auktorisering i ASP.NET Core.
Implementerar CorsApplicationModelProvider beteendet som är associerat med IEnableCorsAttribute och IDisableCorsAttribute. Mer information finns i Aktivera CORS (Cross-Origin Requests) i ASP.NET Core.
Information om ramverkets interna leverantörer som beskrivs i det här avsnittet är inte tillgänglig via .NET API-webbläsaren. Leverantörerna kan dock inspekteras i ASP.NET Core-referenskällan (GitHub-lagringsplatsen dotnet/aspnetcore). Använd GitHub-sökning för att hitta leverantörerna efter namn och välj versionen av källan med listrutan Växla grenar/taggar .
Konventioner
Programmodellen definierar konventionsabstraktioner som ger ett enklare sätt att anpassa modellernas beteende än att åsidosätta hela modellen eller providern. Dessa abstraktioner är det rekommenderade sättet att ändra appens beteende. Konventioner är ett sätt att skriva kod som dynamiskt tillämpar anpassningar. Filter ger ett sätt att ändra ramverkets beteende, men anpassningar ger kontroll över hur hela appen fungerar tillsammans.
Följande konventioner är tillgängliga:
- IApplicationModelConvention
- IControllerModelConvention
- IActionModelConvention
- IParameterModelConvention
Konventioner tillämpas genom att lägga till dem i MVC-alternativ eller genom att implementera attribut och tillämpa dem på kontrollanter, åtgärder eller åtgärdsparametrar (liknar filter). Till skillnad från filter körs konventioner bara när appen startas, inte som en del av varje begäran.
Anmärkning
Information om Razor sidors routnings- och programmodellproviderkonventioner Razor finns i Sidvägs- och appkonventioner i ASP.NET Core.
Ändra ApplicationModel
Följande konvention används för att lägga till en egenskap i programmodellen:
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;
}
}
}
Programmodellkonventioner tillämpas som alternativ när MVC läggs till i Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("My Application Description"));
options.Conventions.Add(new NamespaceRoutingConvention());
});
}
Egenskaper är tillgängliga från ActionDescriptor.Properties samlingen i kontrollantåtgärder:
public class AppModelController : Controller
{
public string Description()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
}
Ändra beskrivningen ControllerModel
Styrenhetsmodellen kan också innehålla anpassade egenskaper. Anpassade egenskaper åsidosätter befintliga egenskaper med samma namn som anges i programmodellen. Följande konventionsattribut lägger till en beskrivning på kontrollantnivå:
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;
}
}
}
Den här konventionen tillämpas som ett attribut på en kontrollant:
[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
public string Index()
{
return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
}
Ändra beskrivningen ActionModel
En separat attributkonvention kan tillämpas på enskilda åtgärder och skriver över beteende som redan tillämpas på applikations- eller kontrollantnivå.
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;
}
}
}
Om du tillämpar detta på en åtgärd inom kontrollanten visas hur den åsidosätter konventionen på kontrollantnivå:
[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"];
}
}
Ändra ParameterModel
Följande konvention kan tillämpas på åtgärdsparametrar för att ändra deras BindingInfo. Följande konvention kräver att parametern är en vägparameter. Andra potentiella bindningskällor, till exempel frågesträngsvärden, ignoreras:
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;
}
}
}
Attributet kan tillämpas på valfri åtgärdsparameter:
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}";
}
}
Om du vill tillämpa konventionen på alla åtgärdsparametrar lägger du till MvcOptions i MustBeInRouteParameterModelConvention i Startup.ConfigureServices:
options.Conventions.Add(new MustBeInRouteParameterModelConvention());
ActionModel Ändra namnet
Följande konvention ändrar ActionModel för att uppdatera namnet på den åtgärd som den tillämpas på. Det nya namnet anges som en parameter för attributet. Det här nya namnet används av routning, så det påverkar den väg som används för att nå den här åtgärdsmetoden:
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;
}
}
}
Det här attributet tillämpas på en åtgärdsmetod i HomeController:
// Route: /Home/MyCoolAction
[CustomActionName("MyCoolAction")]
public string SomeName()
{
return ControllerContext.ActionDescriptor.ActionName;
}
Även om metodnamnet är SomeNameåsidosätter attributet MVC-konventionen om att använda metodnamnet och ersätter åtgärdsnamnet med MyCoolAction. Den väg som används för att nå den här åtgärden är /Home/MyCoolActiondärför .
Anmärkning
Det här exemplet i det här avsnittet är i stort sett detsamma som att använda den inbyggda ActionNameAttribute.
Anpassad routningskonvention
Använd en IApplicationModelConvention för att anpassa hur routning fungerar. Följande konvention innehåller till exempel kontrollernas namnområden i deras rutter och ersätter . i namnområdet med / i rutten:
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
}
}
}
Konventionen läggs till som ett alternativ i Startup.ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.Conventions.Add(new ApplicationDescription("My Application Description"));
options.Conventions.Add(new NamespaceRoutingConvention());
});
}
Tips/Råd
Lägg till konventioner i mellanprogram via MvcOptions följande metod. Platshållaren {CONVENTION} är den konvention som ska läggas till:
services.Configure<MvcOptions>(c => c.Conventions.Add({CONVENTION}));
I följande exempel tillämpas en konvention på vägar som inte använder attributroutning där kontrollanten har Namespace i sitt namn:
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.";
}
}
}
Användning av programmodell i WebApiCompatShim
ASP.NET Core MVC använder en annan uppsättning konventioner från ASP.NET Web API 2. Med hjälp av anpassade konventioner kan du ändra beteendet för en ASP.NET Core MVC-app så att den överensstämmer med beteendet för en webb-API-app. Microsoft levererar WebApiCompatShim NuGet-paketet specifikt för detta ändamål.
Anmärkning
Mer information om migrering från ASP.NET webb-API finns i Migrera från ASP.NET webb-API till ASP.NET Core.
Så här använder du Shim för webb-API:kompatibilitet:
-
Microsoft.AspNetCore.Mvc.WebApiCompatShimLägg till paketet i projektet. - Lägg till konventionerna i MVC genom att anropa AddWebApiConventions i
Startup.ConfigureServices:
services.AddMvc().AddWebApiConventions();
De konventioner som tillhandahålls av shim tillämpas endast på delar av appen som har haft vissa attribut tillämpade på dem. Följande fyra attribut används för att kontrollera vilka kontrollanter som ska få sina konventioner ändrade enligt shim-konventionerna:
- UseWebApiActionConventionsAttribute
- UseWebApiOverloadingAttribute
- UseWebApiParameterConventionsAttribute
- UseWebApiRoutesAttribute
Åtgärdskonventioner
UseWebApiActionConventionsAttribute används för att mappa HTTP-metoden till åtgärder baserat på deras namn (till exempel Get mappas till HttpGet). Det gäller endast åtgärder som inte använder attributroutning.
Överbelastning
UseWebApiOverloadingAttribute används för att tillämpa konventionen WebApiOverloadingApplicationModelConvention . Den här konventionen lägger till en OverloadActionConstraint till åtgärdsvalsprocessen, vilket begränsar kandidatåtgärderna till de för vilka begäran uppfyller alla icke-valfria parametrar.
Parameterkonventioner
UseWebApiParameterConventionsAttribute används för att tillämpa åtgärdskonventionen WebApiParameterConventionsApplicationModelConvention . Den här konventionen anger att enkla typer som används som åtgärdsparametrar är bundna från URI:n som standard, medan komplexa typer är bundna från begärandetexten.
Vägar
UseWebApiRoutesAttribute styr om WebApiApplicationModelConvention kontrollantkonventionen tillämpas. När den här konventionen är aktiverad används den för att lägga till stöd för områden i vägen och anger att kontrollanten finns i området api .
Förutom en uppsättning konventioner innehåller kompatibilitetspaketet en System.Web.Http.ApiController basklass som ersätter den som tillhandahålls av webb-API:et. Detta gör att dina webb-API-kontroller som är skrivna för webb-API och ärver från ApiController kan fungera när de körs på ASP.NET Core MVC. Alla UseWebApi* attribut som listats tidigare tillämpas på bascontroller-klassen. Exponerar ApiController egenskaper, metoder och resultattyper som är kompatibla med dem som finns i webb-API:et.
Använda ApiExplorer för att dokumentera en app
Programmodellen exponerar en ApiExplorerModel egenskap på varje nivå som kan användas för att gå igenom appens struktur. Detta kan användas för att generera hjälpsidor för webb-API:er med hjälp av verktyg som Swagger. Egenskapen ApiExplorer exponerar en IsVisible egenskap som kan anges för att ange vilka delar av appens modell som ska exponeras. Konfigurera den här inställningen med hjälp av en konvention:
using Microsoft.AspNetCore.Mvc.ApplicationModels;
namespace AppModelSample.Conventions
{
public class EnableApiExplorerApplicationConvention : IApplicationModelConvention
{
public void Apply(ApplicationModel application)
{
application.ApiExplorer.IsVisible = true;
}
}
}
Med den här metoden (och ytterligare konventioner om det behövs) aktiveras eller inaktiveras API-synlighet på alla nivåer i en app.
ASP.NET Core