Sdílet prostřednictvím


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
    • Kontroléry (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 jsou uloženy do ActionDescriptor.Properties při 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í poskytovatelského vzoru je pokročilé téma, primárně určené pro použití ve frameworku. Většina aplikací by měla používat konvence, ne model poskytovatele.

Implementace rozhraní IApplicationModelProvider jsou navzájem "obalená", kde každá implementace volá OnProvidersExecuting ve vzestupném pořadí na základě své vlastnosti Order. 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, který mohou autoři frameworku rozšiřovat. 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 mají přednost před pravidly.

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í veřejných metod 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ána DefaultApplicationModelProvider. Tento poskytovatel je zodpovědný za vytvoření ControllerModel, který následně odkazuje ActionModel, PropertyModel a ParameterModel instance. Třída DefaultApplicationModelProvider je podrobnost implementace interního rámce, která se může v budoucnu změnit.

Zodpovídá AuthorizationApplicationModelProvider za použití chování spojeného s atributy AuthorizeFilter a AllowAnonymousFilter. 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é mohou 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 pro konvence, které poskytují jednodušší způsob přizpůsobení modelového chování než nahrazení 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ématuRazor 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

K jednotlivým akcím lze použít samostatnou konvenci atributů, která přepíše chování již použité na úrovni aplikace nebo řadiče.

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

Aplikace tohoto na akci v kontroléru ukazuje, jak přepisuje konvenci na úrovni kontroléru:

[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 ke parametrům 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 MustBeInRouteParameterModelConvention do MvcOptions v Startup.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 tedy /Home/MyCoolAction.

Poznámka:

Tento příklad je v podstatě stejný jako použití vestavěného ActionNameAttribute.

Vlastní konvence směrování

Pomocí IApplicationModelConvention přizpůsobte fungování směrování. Například následující konvence zahrnuje jmenné prostory kontrolerů do jejich tras, přičemž v jmenném prostoru nahrazuje . za / v trase:

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

Návod

Pomocí následujícího přístupu přidejte konvence do middlewaruMvcOptions. Zástupný prvek {CONVENTION} se přidává podle konvence:

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.

Chcete-li použít vrstvu pro kompatibilitu 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é vrstvou se použijí pouze na ty části aplikace, které mají 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 k procesu výběru akce, který omezuje kandidátské akce na ty, pro které požadavek splňuje všechny povinné 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, které jsou napsané pro webové rozhraní API a dědí z ApiController, fungovaly při běhu na ASP.NET Core MVC. UseWebApi* Všechny dříve uvedené atributy se použijí na základní třídu kontroleru. Zpřístupňuje ApiController vlastnosti, metody a typy výsledků, které jsou kompatibilní s těmi, které se nacházejí 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.