Práce s aplikačním modelem v ASP.NET Core

Autor: Steve Smith

ASP.NET Core MVC definuje aplikační model představující komponenty aplikace MVC. Přečtěte si a manipulujte s tímto modelem a upravte chování prvků MVC. MVC ve výchozím nastavení dodržuje určité konvence k určení tříd, které třídy jsou považovány za kontrolery, které metody v těchto třídách jsou akce a jak se parametry a směrování chovají. Přizpůsobte si toto chování tak, aby vyhovovalo potřebám aplikace, a to tak, že vytvoříte vlastní konvence a použijete je globálně nebo jako atributy.

Modely a poskytovatelé (IApplicationModelProvider)

Aplikační model ASP.NET Core MVC zahrnuje jak abstraktní rozhraní, tak konkrétní třídy implementace, které popisují aplikaci MVC. Tento model je výsledkem MVC, který zjišťuje kontrolery, akce, parametry akcí, trasy a filtry podle výchozích konvencí. Když pracujete s aplikačním modelem, upravte aplikaci tak, aby dodržovala různé konvence z výchozího chování MVC. Parametry, názvy, trasy a filtry se používají jako konfigurační data pro akce a kontrolery.

Aplikační model ASP.NET Core MVC má následující strukturu:

  • ApplicationModel
    • Kontrolery (ControllerModel)
      • Akce (ActionModel)
        • Parametry (ParameterModel)

Každá úroveň modelu má přístup ke společné Properties kolekci a nižší úrovně můžou přistupovat k hodnotám vlastností nastaveným vyššími úrovněmi v hierarchii a přepsat je. Vlastnosti se zachovají při ActionDescriptor.Properties vytváření akcí. Když se pak zpracovává požadavek, dají se ke všem vlastnostem přidané nebo upravené konvence přistupovat prostřednictvím ActionContext.ActionDescriptor. Použití vlastností je skvělý způsob, jak nakonfigurovat filtry, pořadače modelů a další aspekty modelu aplikace na základě jednotlivých akcí.

Poznámka

Kolekce ActionDescriptor.Properties po spuštění aplikace není bezpečná pro přístup z více vláken (pro zápisy). Konvence představují nejlepší způsob, jak bezpečně přidávat data do této kolekce.

ASP.NET Core MVC načte aplikační model pomocí vzoru zprostředkovatele definovaného rozhraním IApplicationModelProvider . Tato část se věnuje některým interním podrobnostem implementace, jak tento poskytovatel funguje. Použití vzoru poskytovatele je pokročilý předmět, především pro použití architektury. Většina aplikací by měla používat konvence, ne model poskytovatele.

IApplicationModelProvider Implementace rozhraní "wrap" navzájem, kde každá implementace volá OnProvidersExecuting ve vzestupném pořadí na základě své Order vlastnosti. Metoda OnProvidersExecuted se pak volá v obráceném pořadí. Architektura definuje několik poskytovatelů:

První (Order=-1000):

  • DefaultApplicationModelProvider

Pak (Order=-990):

  • AuthorizationApplicationModelProvider
  • CorsApplicationModelProvider

Poznámka

Pořadí, ve kterém jsou voláni dva poskytovatelé se stejnou hodnotou Order , není definováno a nemělo by se spoléhat na.

Poznámka

IApplicationModelProvider je pokročilý koncept pro autory architektury, které se mají rozšířit. Obecně platí, že aplikace by měly používat konvence a architektury by měly používat poskytovatele. Klíčovým rozdílem je, že poskytovatelé vždy běží před konvencemi.

Určuje DefaultApplicationModelProvider mnoho výchozích chování používaných ASP.NET Core MVC. Mezi její povinnosti patří:

  • Přidání globálních filtrů do kontextu
  • Přidání kontrolerů do kontextu
  • Přidání metod veřejného kontroleru jako akcí
  • Přidání parametrů metody akce do kontextu
  • Použití trasy a dalších atributů

Některé předdefinované chování jsou implementovány DefaultApplicationModelProvider. Tento poskytovatel je zodpovědný za vytvoření ControllerModel, který následně odkazuje ActionModel, PropertyModela ParameterModel instance. Třída DefaultApplicationModelProvider je podrobnosti implementace interní architektury, které se mohou v budoucnu změnit.

Zodpovídá AuthorizationApplicationModelProvider za použití chování spojeného s atributy AuthorizeFilter a AllowAnonymousFilter atributy. Další informace najdete v tématu Jednoduchá autorizace v ASP.NET Core.

Implementuje CorsApplicationModelProvider chování spojené s IEnableCorsAttribute a IDisableCorsAttribute. Další informace najdete v tématu Povolení žádostí mezi zdroji (CORS) v ASP.NET Core.

Informace o interních poskytovatelích architektury popsané v této části nejsou dostupné prostřednictvím prohlížeče rozhraní .NET API. Poskytovatelé ale můžou být zkontrolováni v referenčním zdroji ASP.NET Core (úložiště dotnet/aspnetcore Na GitHubu). Pomocí vyhledávání v GitHubu vyhledejte zprostředkovatele podle názvu a vyberte verzi zdroje pomocí rozevíracího seznamu Přepnout větve/značky .

Konvence

Aplikační model definuje abstrakce konvence, které poskytují jednodušší způsob přizpůsobení chování modelů než přepsání celého modelu nebo poskytovatele. Tyto abstrakce představují doporučený způsob, jak upravit chování aplikace. Konvence poskytují způsob psaní kódu, který dynamicky používá vlastní nastavení. I když filtry poskytují způsob úpravy chování architektury, vlastní nastavení umožňují řídit, jak celá aplikace funguje společně.

K dispozici jsou následující konvence:

Konvence se použijí přidáním do možností MVC nebo implementací atributů a jejich použitím na kontrolery, akce nebo parametry akce (podobně jako u filtrů). Na rozdíl od filtrů se konvence spouští jenom při spuštění aplikace, ne jako součást každého požadavku.

Poznámka

Informace o Razor konvencích směrování stránek a poskytovatelů aplikačních modelů najdete v tématu Razor Stránky – trasy a konvence aplikací v ASP.NET Core.

Úprava ApplicationModel

K přidání vlastnosti do aplikačního modelu se používá následující konvence:

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

Konvence aplikačního modelu se použijí jako možnosti při přidání MVC do Startup.ConfigureServices:

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

Vlastnosti jsou přístupné z ActionDescriptor.Properties kolekce v rámci akcí kontroleru:

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

ControllerModel Úprava popisu

Model kontroleru může obsahovat také vlastní vlastnosti. Vlastní vlastnosti přepíší existující vlastnosti se stejným názvem zadaným v aplikačním modelu. Následující atribut konvence přidá popis na úrovni kontroleru:

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

Tato konvence se použije jako atribut kontroleru:

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

ActionModel Úprava popisu

Samostatnou konvenci atributů lze použít pro jednotlivé akce, přepsání chování již použité na úrovni aplikace nebo kontroleru:

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

Použití této akce na akci v kontroleru ukazuje, jak přepisuje konvenci na úrovni kontroleru:

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

Úprava ParameterModel

Následující konvence lze použít pro parametry akce pro úpravu jejich BindingInfo. Následující konvence vyžaduje, aby parametr byl parametrem trasy. Další potenciální zdroje vazeb, jako jsou například hodnoty řetězce dotazu, se ignorují:

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

Atribut se může použít u libovolného parametru akce:

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

Pokud chcete konvenci použít pro všechny parametry akce, přidejte do MustBeInRouteParameterModelConvention :MvcOptionsStartup.ConfigureServices

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

ActionModel Úprava názvu

Následující konvence upraví ActionModel tak, aby aktualizoval název akce, na kterou se používá. Nový název je zadaný jako parametr atributu. Tento nový název se používá směrováním, takže ovlivňuje trasu použitou k dosažení této metody akce:

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

Tento atribut se použije na metodu akce v :HomeController

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

I když je SomeNamenázev metody , atribut přepíše konvenci MVC použití názvu metody a nahradí název akce názvem MyCoolAction. Trasa použitá k dosažení této akce je /Home/MyCoolActiontedy .

Poznámka

Tento příklad v této části je v podstatě stejný jako použití integrované ActionNameAttribute.

Vlastní konvence směrování

IApplicationModelConvention Umožňuje přizpůsobit fungování směrování. Následující konvence například zahrnuje obory názvů kontrolerů do jejich tras a nahrazuje . ho v oboru názvů / trasou:

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

Konvence se přidá jako možnost v Startup.ConfigureServices:

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

Tip

Pomocí následujícího přístupu přidejte konvence do middlewaruMvcOptions. Zástupný {CONVENTION} symbol je konvence, která se má přidat:

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

Následující příklad používá konvenci pro trasy, které nepoužívají směrování atributů, kde má kontroler Namespace ve svém názvu:

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

Využití aplikačního modelu v WebApiCompatShim

ASP.NET Core MVC používá jinou sadu konvencí od ASP.NET webového rozhraní API 2. Pomocí vlastních konvencí můžete upravit chování aplikace ASP.NET Core MVC tak, aby bylo konzistentní s chováním aplikace webového rozhraní API. Microsoft dodává WebApiCompatShim balíček NuGet speciálně pro tento účel.

Poznámka

Další informace o migraci z webového rozhraní API ASP.NET najdete v tématu Migrace z webového rozhraní API ASP.NET na ASP.NET Core.

Použití shimu kompatibility webového rozhraní API:

  • Přidejte balíček Microsoft.AspNetCore.Mvc.WebApiCompatShim do projektu.
  • Přidejte konvence do MVC voláním AddWebApiConventionsStartup.ConfigureServices:
services.AddMvc().AddWebApiConventions();

Konvence poskytované překrytí se použijí jenom na části aplikace, u kterých byly použity určité atributy. Následující čtyři atributy slouží k řízení, které kontrolery mají mít své konvence změněné konvencemi shim:

Konvence akcí

UseWebApiActionConventionsAttribute slouží k mapování metody HTTP na akce na základě jejich názvu (například Get by mapoval na HttpGet). Platí jenom pro akce, které nepoužívají směrování atributů.

Přetížení

UseWebApiOverloadingAttribute se používá k použití WebApiOverloadingApplicationModelConvention konvence. Tato konvence přidá OverloadActionConstraint proces výběru akce, který omezuje kandidátské akce na ty, pro které požadavek splňuje všechny nepovinné parametry.

Konvence parametrů

UseWebApiParameterConventionsAttribute se používá k použití WebApiParameterConventionsApplicationModelConvention konvence akce. Tato konvence určuje, že jednoduché typy používané jako parametry akce jsou ve výchozím nastavení vázány z identifikátoru URI, zatímco složité typy jsou vázány z textu požadavku.

Trasy

UseWebApiRoutesAttribute určuje, zda WebApiApplicationModelConvention se používá konvence kontroleru. Pokud je tato konvence povolená, slouží k přidání podpory oblastí na trasu a označuje, že kontroler je v api dané oblasti.

Kromě sady konvencí zahrnuje System.Web.Http.ApiController balíček kompatibility základní třídu, která nahrazuje třídu poskytovanou webovým rozhraním API. To umožňuje, aby řadiče webového rozhraní API napsané pro webové rozhraní API a dědily z toho ApiController , aby fungovaly při spouštění na ASP.NET Core MVC. UseWebApi* Všechny dříve uvedené atributy se použijí na základní třídu kontroleru. Zveřejňuje ApiController vlastnosti, metody a typy výsledků, které jsou kompatibilní s vlastnostmi nalezenými ve webovém rozhraní API.

Použití ApiExplorer k dokumentaci aplikace

Aplikační model zveřejňuje ApiExplorerModel vlastnost na každé úrovni, kterou lze použít k procházení struktury aplikace. Dá se použít ke generování stránek nápovědy pro webová rozhraní API pomocí nástrojů, jako je Swagger. Tato ApiExplorer vlastnost zveřejňuje IsVisible vlastnost, která se dá nastavit tak, aby určila, které části modelu aplikace mají být vystaveny. Nakonfigurujte toto nastavení pomocí konvence:

using Microsoft.AspNetCore.Mvc.ApplicationModels;

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

Použití tohoto přístupu (a dalších konvencí v případě potřeby) je viditelnost rozhraní API povolená nebo zakázaná na jakékoli úrovni v rámci aplikace.