Delen via


Werken met het toepassingsmodel in ASP.NET Core

Door Steve Smith

ASP.NET Core MVC definieert een toepassingsmodel dat de onderdelen van een MVC-app vertegenwoordigt. Lees en bewerk dit model om te wijzigen hoe MVC-elementen zich gedragen. Standaard volgt MVC bepaalde conventies om te bepalen welke klassen worden beschouwd als controllers, welke methoden voor deze klassen acties zijn en hoe parameters en routering zich gedragen. Pas dit gedrag aan aan de behoeften van een app aan door aangepaste conventies te maken en ze globaal of als kenmerken toe te passen.

Modellen en leveranciers (IApplicationModelProvider)

Het ASP.NET Core MVC-toepassingsmodel bevat zowel abstracte interfaces als concrete implementatieklassen die een MVC-toepassing beschrijven. Dit model is het resultaat van het detecteren van de controllers, acties, actieparameters, routes en filters van de app volgens de standaardconventies. Door met het toepassingsmodel te werken, wijzigt u een app om verschillende conventies te volgen op basis van het standaard MVC-gedrag. De parameters, namen, routes en filters worden allemaal gebruikt als configuratiegegevens voor acties en controllers.

Het ASP.NET Core MVC-toepassingsmodel heeft de volgende structuur:

  • Applicatiemodel
    • Controllers (ControllerModel)
      • Actions (ActionModel)
        • Parameters (ParameterModel)

Elk niveau van het model heeft toegang tot een gemeenschappelijke Properties verzameling en lagere niveaus kunnen eigenschapswaarden openen en overschrijven die zijn ingesteld door hogere niveaus in de hiërarchie. De eigenschappen worden opgeslagen in de ActionDescriptor.Properties wanneer de acties worden aangemaakt. Wanneer een aanvraag vervolgens wordt verwerkt, kunnen alle eigenschappen die door een conventie worden toegevoegd of gewijzigd, worden geopend via ActionContext.ActionDescriptor. Het gebruik van eigenschappen is een uitstekende manier om filters, modelbindingen en andere aspecten van het app-model per actie te configureren.

Opmerking

De ActionDescriptor.Properties verzameling is niet thread-veilig (voor schrijfbewerkingen) na het opstarten van de app. Conventies zijn de beste manier om veilig gegevens aan deze verzameling toe te voegen.

ASP.NET Core MVC laadt het toepassingsmodel met behulp van een providerpatroon dat is gedefinieerd door de IApplicationModelProvider interface. In deze sectie vindt u informatie over de interne implementatie van de werking van deze provider. Het gebruik van het providerpatroon is een geavanceerd onderwerp, voornamelijk voor frameworkgebruik. De meeste apps moeten conventies gebruiken, niet het providerpatroon.

Implementaties van de IApplicationModelProvider interface omwikkelen elkaar, waarbij elke implementatie OnProvidersExecuting in oplopende volgorde aanroept op basis van de Order eigenschap. De OnProvidersExecuted methode wordt vervolgens in omgekeerde volgorde aangeroepen. Het framework definieert verschillende providers:

Eerst (Order=-1000):

  • DefaultApplicationModelProvider

Vervolgens (Order=-990):

  • AuthorizationApplicationModelProvider
  • CorsApplicationModelProvider

Opmerking

De volgorde waarin twee providers met dezelfde waarde Order worden aangeroepen, is niet gedefinieerd en mag niet worden vertrouwd.

Opmerking

IApplicationModelProvider is een geavanceerd concept dat auteurs van frameworks kunnen uitbreiden. Over het algemeen moeten apps gebruikmaken van conventies en frameworks moeten providers gebruiken. Het belangrijkste onderscheid is dat providers altijd vóór conventies draaien.

Hiermee DefaultApplicationModelProvider worden veel van de standaardgedragen vastgesteld die worden gebruikt door ASP.NET Core MVC. De verantwoordelijkheden zijn onder andere:

  • Globale filters toevoegen aan de context
  • Controllers toevoegen aan de context
  • Openbare controllermethoden toevoegen als acties
  • Parameters voor actiemethode toevoegen aan de context
  • Route en andere kenmerken toepassen

Sommige ingebouwde gedragingen worden geïmplementeerd door de DefaultApplicationModelProvider. Deze provider is verantwoordelijk voor het samenstellen van de ControllerModel, die op zijn beurt verwijst naar ActionModel, PropertyModelen ParameterModel instanties. De DefaultApplicationModelProvider klasse is een intern framework-implementatiedetail dat in de toekomst kan veranderen.

De AuthorizationApplicationModelProvider is verantwoordelijk voor het toepassen van het gedrag dat is gekoppeld aan de AuthorizeFilter en AllowAnonymousFilter kenmerken. Zie Eenvoudige autorisatie in ASP.NET Core voor meer informatie.

Het CorsApplicationModelProvider implementeert gedrag dat is gekoppeld aan IEnableCorsAttribute en IDisableCorsAttribute. Zie Cross-Origin Requests (CORS) inschakelen in ASP.NET Corevoor meer informatie.

Informatie over de interne providers van het framework die in deze sectie worden beschreven, zijn niet beschikbaar via de .NET API-browser. De providers kunnen echter worden geïnspecteerd in de ASP.NET Core-referentiebron (dotnet/aspnetcore GitHub-opslagplaats). Gebruik GitHub Search om de providers op naam te zoeken en selecteer de versie van de bron met de vervolgkeuzelijst Switch-vertakkingen/tags .

Verdragen

Het toepassingsmodel definieert conventieabstracties die een eenvoudigere manier bieden om het gedrag van de modellen aan te passen dan het hele model of de hele provider te overschrijven. Deze abstracties zijn de aanbevolen manier om het gedrag van een app te wijzigen. Conventies bieden een manier om code te schrijven die dynamisch aanpassingen toepast. Hoewel filters een middel bieden om het gedrag van het framework te wijzigen, bieden aanpassingen controle over de werking van de hele app.

De volgende conventies zijn beschikbaar:

Conventies worden toegepast door ze toe te voegen aan MVC-opties of door kenmerken te implementeren en toe te passen op controllers, acties of actieparameters (vergelijkbaar met filters). In tegenstelling tot filters worden conventies alleen uitgevoerd wanneer de app wordt gestart, niet als onderdeel van elke aanvraag.

Opmerking

Zie Razor Pagina-routes en app-conventies in ASP.NET CoreRazor voor informatie over de conventies van de Pagina-route- en toepassingsmodelprovider.

Wijzig de ApplicationModel

De volgende conventie wordt gebruikt om een eigenschap toe te voegen aan het toepassingsmodel:

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;
        }
    }
}

Toepassingsmodelconventies worden toegepast als opties wanneer MVC wordt toegevoegd in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Conventions.Add(new ApplicationDescription("My Application Description"));
        options.Conventions.Add(new NamespaceRoutingConvention());
    });
}

Eigenschappen zijn toegankelijk vanuit de ActionDescriptor.Properties verzameling binnen controlleracties:

public class AppModelController : Controller
{
    public string Description()
    {
        return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
    }
}

ControllerModel De beschrijving wijzigen

Het controllermodel kan ook aangepaste eigenschappen bevatten. Aangepaste eigenschappen overschrijven bestaande eigenschappen met dezelfde naam die is opgegeven in het toepassingsmodel. Met het volgende conventiekenmerk wordt een beschrijving toegevoegd op controllerniveau:

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;
        }
    }
}

Deze conventie wordt toegepast als een kenmerk op een controller:

[ControllerDescription("Controller Description")]
public class DescriptionAttributesController : Controller
{
    public string Index()
    {
        return "Description: " + ControllerContext.ActionDescriptor.Properties["description"];
    }

ActionModel De beschrijving wijzigen

Er kan een afzonderlijke kenmerkconventie worden toegepast op afzonderlijke acties, waarbij het gedrag dat al op toepassings- of controllerniveau is toegepast, wordt overschreven:

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;
        }
    }
}

Als u dit toepast op een actie binnen de controller, ziet u hoe deze de conventie op controllerniveau overschrijft:

[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"];
    }
}

Wijzig de ParameterModel

De volgende conventie kan worden toegepast op actieparameters om hun BindingInfote wijzigen. De volgende conventie vereist dat de parameter een routeparameter is. Andere mogelijke bindingsbronnen, zoals queryreekswaarden, worden genegeerd:

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;
        }
    }
}

Het kenmerk kan worden toegepast op een actieparameter:

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}";
    }
}

Als u de conventie wilt toepassen op alle actieparameters, voegt u de MustBeInRouteParameterModelConvention aan toe in MvcOptionsStartup.ConfigureServices:

options.Conventions.Add(new MustBeInRouteParameterModelConvention());

ActionModel De naam wijzigen

De volgende conventie wijzigt de ActionModel om de naam van de actie waarop deze wordt toegepast bij te werken. De nieuwe naam wordt opgegeven als een parameter voor het kenmerk. Deze nieuwe naam wordt gebruikt door routering, dus dit is van invloed op de route die wordt gebruikt om deze actiemethode te bereiken:

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;
        }
    }
}

Dit kenmerk wordt toegepast op een actiemethode in het HomeControllervolgende:

// Route: /Home/MyCoolAction
[CustomActionName("MyCoolAction")]
public string SomeName()
{
    return ControllerContext.ActionDescriptor.ActionName;
}

Hoewel de naam van de methode is SomeName, overschrijft het kenmerk de MVC-conventie van het gebruik van de methodenaam en vervangt de actienaam door MyCoolAction. De route die wordt gebruikt om deze actie te bereiken, is /Home/MyCoolActiondus .

Opmerking

Dit voorbeeld in deze sectie is in feite hetzelfde als het gebruik van de ingebouwde ActionNameAttribute.

Aangepaste routeringsconventie

Gebruik een IApplicationModelConvention om aan te passen hoe routering werkt. De volgende conventie neemt bijvoorbeeld de naamruimten van controllers op in hun routes, waarbij `.` in de naamruimte wordt vervangen door `/` in de route.

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
        }
    }
}

De conventie wordt toegevoegd als een optie in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options =>
    {
        options.Conventions.Add(new ApplicationDescription("My Application Description"));
        options.Conventions.Add(new NamespaceRoutingConvention());
    });
}

Aanbeveling

Voeg conventies toe aan middleware via MvcOptions de volgende methode. De {CONVENTION} tijdelijke aanduiding is de conventie die u wilt toevoegen:

services.Configure<MvcOptions>(c => c.Conventions.Add({CONVENTION}));

In het volgende voorbeeld wordt een conventie toegepast op routes die geen kenmerkroutering gebruiken waarbij de controller de naam heeft 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.";
        }
    }
}

Gebruik van toepassingsmodel in WebApiCompatShim

ASP.NET Core MVC maakt gebruik van een andere set conventies dan ASP.NET Web-API 2. Met behulp van aangepaste conventies kunt u het gedrag van een ASP.NET Core MVC-app wijzigen zodat deze consistent is met die van een web-API-app. Microsoft verzendt het WebApiCompatShim NuGet-pakket specifiek voor dit doel.

De Web API Compatibility Shim gebruiken:

  • Voeg het Microsoft.AspNetCore.Mvc.WebApiCompatShim pakket toe aan het project.
  • Voeg de conventies toe aan MVC door AddWebApiConventions aan te roepen in Startup.ConfigureServices:
services.AddMvc().AddWebApiConventions();

De conventies van de shim worden alleen toegepast op onderdelen van de app waarop bepaalde kenmerken zijn toegepast. De volgende vier attributen worden gebruikt om te bepalen welke controllers hun conventies moeten laten wijzigen door de conventies van de shim.

Actieconventies

UseWebApiActionConventionsAttribute wordt gebruikt om de HTTP-methode toe te wijzen aan acties op basis van hun naam (bijvoorbeeld Get wordt toegewezen aan HttpGet). Dit geldt alleen voor acties die geen kenmerkroutering gebruiken.

Overbelasting

UseWebApiOverloadingAttribute wordt gebruikt om de WebApiOverloadingApplicationModelConvention conventie toe te passen. Deze conventie voegt een OverloadActionConstraint toe aan het actieselectieproces, waarmee kandidaatacties worden beperkt tot acties waarvoor de aanvraag voldoet aan alle niet-optionele parameters.

Parameter conventies

UseWebApiParameterConventionsAttribute wordt gebruikt om de WebApiParameterConventionsApplicationModelConvention actieconventie toe te passen. Deze conventie geeft aan dat eenvoudige typen die worden gebruikt als actieparameters standaard afhankelijk zijn van de URI, terwijl complexe typen afhankelijk zijn van de hoofdtekst van de aanvraag.

Routen

UseWebApiRoutesAttribute bepaalt of de WebApiApplicationModelConvention controllerconventie wordt toegepast. Indien ingeschakeld, wordt deze conventie gebruikt om ondersteuning voor gebieden aan de route toe te voegen en geeft aan dat de controller zich in het api gebied bevindt.

Naast een set conventies bevat het compatibiliteitspakket een System.Web.Http.ApiController basisklasse die de klasse vervangt die wordt geleverd door de web-API. Hierdoor kunnen uw web-API-controllers, die zijn geschreven voor de web-API en overnemen van zijn ApiController, werken terwijl ze worden uitgevoerd op ASP.NET Core MVC. UseWebApi* Alle kenmerken die eerder worden vermeld, worden toegepast op de basiscontrollerklasse. Hiermee ApiController worden eigenschappen, methoden en resultaattypen weergegeven die compatibel zijn met de typen die zijn gevonden in de web-API.

Gebruiken ApiExplorer om een app te documenteren

Het toepassingsmodel maakt een ApiExplorerModel eigenschap beschikbaar op elk niveau dat kan worden gebruikt om de structuur van de app te doorlopen. Dit kan worden gebruikt om Help-pagina's voor web-API's te genereren met behulp van hulpprogramma's zoals Swagger. Met ApiExplorer de eigenschap wordt een IsVisible eigenschap weergegeven die kan worden ingesteld om op te geven welke onderdelen van het app-model moeten worden weergegeven. Configureer deze instelling met behulp van een conventie:

using Microsoft.AspNetCore.Mvc.ApplicationModels;

namespace AppModelSample.Conventions
{
    public class EnableApiExplorerApplicationConvention : IApplicationModelConvention
    {
        public void Apply(ApplicationModel application)
        {
            application.ApiExplorer.IsVisible = true;
        }
    }
}

Met deze methode (en indien nodig aanvullende conventies) wordt API-zichtbaarheid ingeschakeld of uitgeschakeld op elk niveau binnen een app.