Vazba modelu v ASP.NET Core

Tento článek vysvětluje, co je vazba modelu, jak funguje a jak přizpůsobit jeho chování.

Co je vazba modelu

Kontrolery a Razor stránky pracují s daty pocházejícími z požadavků HTTP. Například směrovací data můžou poskytnout klíč záznamu a zaúčtované pole formuláře můžou poskytovat hodnoty vlastností modelu. Psaní kódu pro načtení každé z těchto hodnot a jejich převod z řetězců na typy .NET by bylo zdlouhavé a náchylné k chybám. Vazba modelu tento proces automatizuje. Systém vazeb modelu:

  • Načte data z různých zdrojů, jako jsou směrování dat, pole formuláře a řetězce dotazů.
  • Poskytuje data řadičům a Razor stránkám v parametrech metody a veřejných vlastnostech.
  • Převede řetězcová data na typy .NET.
  • Aktualizuje vlastnosti složitých typů.

Příklad

Předpokládejme, že máte následující metodu akce:

[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)

Aplikace obdrží žádost s touto adresou URL:

https://contoso.com/api/pets/2?DogsOnly=true

Vazba modelu prochází následujícími kroky poté, co systém směrování vybere metodu akce:

  • Najde první parametr GetByIdinteger s názvem id.
  • Projde dostupné zdroje v požadavku HTTP a najde id = "2" ve směrovacích datech.
  • Převede řetězec "2" na celé číslo 2.
  • Najde další parametr logické hodnoty GetByIds názvem dogsOnly.
  • Vyhledá zdroje a najde v řetězci dotazu "DogsOnly=true". Porovnávání názvů nerozlišuje malá a velká písmena.
  • Převede řetězec "true" na logickou truehodnotu .

Architektura pak volá metodu GetById , předání 2 parametru id a true parametru dogsOnly .

V předchozím příkladu jsou cíle vazby modelu parametry metody, které jsou jednoduché typy. Cíle můžou být také vlastnosti komplexního typu. Po úspěšném vázaní každé vlastnosti dojde k ověření modelu pro danou vlastnost. Záznam dat, která data jsou svázána s modelem, a všechny chyby vazby nebo ověření, jsou uloženy v ControllerBase.ModelState nebo PageModel.ModelState. Pokud chcete zjistit, jestli byl tento proces úspěšný, aplikace zkontroluje příznak ModelState.IsValid .

Targets

Vazba modelu se pokouší najít hodnoty pro následující typy cílů:

  • Parametry metody akce kontroleru, do které je požadavek směrován.
  • Razor Parametry metody obslužné rutiny Pages, do které je požadavek směrován.
  • Veřejné vlastnosti kontroleru nebo PageModel třídy, pokud jsou určeny atributy.

Atribut [BindProperty]

Lze použít na veřejnou vlastnost kontroleru nebo PageModel třídy, která způsobí, že vazba modelu bude cílit na tuto vlastnost:

public class EditModel : PageModel
{
    [BindProperty]
    public Instructor? Instructor { get; set; }

    // ...
}

Atribut [BindProperties]

Lze použít u kontroleru nebo PageModel třídy, aby bylo možné určit vazbu modelu tak, aby cílila na všechny veřejné vlastnosti třídy:

[BindProperties]
public class CreateModel : PageModel
{
    public Instructor? Instructor { get; set; }

    // ...
}

Vazba modelu pro požadavky HTTP GET

Ve výchozím nastavení nejsou vlastnosti vázané na požadavky HTTP GET. Obvykle je vše, co potřebujete pro požadavek GET, parametr ID záznamu. ID záznamu slouží k vyhledání položky v databázi. Proto není nutné vytvořit vazbu vlastnosti, která obsahuje instanci modelu. Ve scénářích, ve kterých chcete, aby vlastnosti vázané na data z požadavků GET, nastavte SupportsGet vlastnost na true:

[BindProperty(Name = "ai_user", SupportsGet = true)]
public string? ApplicationInsightsCookie { get; set; }

zdroje

Vazba modelu ve výchozím nastavení získává data ve formě párů klíč-hodnota z následujících zdrojů v požadavku HTTP:

  1. Pole formuláře
  2. Text požadavku (pro kontrolery, které mají atribut [ApiController].)
  3. Směrování dat
  4. Parametry řetězce dotazu
  5. Nahrané soubory

Pro každý cílový parametr nebo vlastnost se zdroje prohledávají v pořadí uvedeném v předchozím seznamu. Existuje několik výjimek:

  • Směrovací data a řetězcové hodnoty dotazu se používají pouze pro jednoduché typy.
  • Nahrané soubory jsou vázané pouze na cílové typy, které implementují IFormFile nebo IEnumerable<IFormFile>.

Pokud výchozí zdroj není správný, zadejte zdroj jedním z následujících atributů:

  • [FromQuery] – Získá hodnoty z řetězce dotazu.
  • [FromRoute] - Získá hodnoty ze směrovacích dat.
  • [FromForm] - Získá hodnoty z publikovaných polí formuláře.
  • [FromBody] - Získá hodnoty z textu požadavku.
  • [FromHeader] – Získá hodnoty z hlaviček HTTP.

Tyto atributy:

  • Jsou přidány do vlastností modelu jednotlivě, nikoli do třídy modelu, jako v následujícím příkladu:

    public class Instructor
    {
        public int Id { get; set; }
    
        [FromQuery(Name = "Note")]
        public string? NoteFromQueryString { get; set; }
    
        // ...
    }
    
  • Volitelně můžete v konstruktoru přijmout hodnotu názvu modelu. Tato možnost je k dispozici v případě, že název vlastnosti neodpovídá hodnotě v požadavku. Například hodnota v požadavku může být záhlavím s pomlčkam v názvu, jako v následujícím příkladu:

    public void OnGet([FromHeader(Name = "Accept-Language")] string language)
    

Atribut [FromBody]

Pomocí atributu [FromBody] na parametr naplníte jeho vlastnosti z textu požadavku HTTP. Modul runtime ASP.NET Core deleguje odpovědnost za čtení textu na vstupní formátovač. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.

Při [FromBody] použití u komplexního parametru typu se všechny atributy zdroje vazby použité na jeho vlastnosti ignorují. Například následující Create akce určuje, že se jeho pet parametr naplní z textu:

public ActionResult<Pet> Create([FromBody] Pet pet)

Třída Pet určuje, že její Breed vlastnost je naplněna z parametru řetězce dotazu:

public class Pet
{
    public string Name { get; set; } = null!;

    [FromQuery] // Attribute is ignored.
    public string Breed { get; set; } = null!;
}

V předchozím příkladu:

  • Atribut [FromQuery] se ignoruje.
  • Vlastnost Breed není naplněna parametrem řetězce dotazu.

Vstupní formátovací moduly čtou jenom text a nerozumí zdrojovým atributům vazby. Pokud je v textu nalezena vhodná hodnota, tato hodnota se použije k naplnění Breed vlastnosti.

Nevztahuje se [FromBody] na více než jeden parametr na metodu akce. Jakmile datový proud požadavku přečte vstupní formátovací modul, už není k dispozici ke čtení pro vazbu dalších [FromBody] parametrů.

Další zdroje

Zdrojová data jsou poskytována systému vazby modelu poskytovateli hodnot. Můžete napsat a zaregistrovat vlastní zprostředkovatele hodnot, kteří získávají data pro vazbu modelu z jiných zdrojů. Můžete například chtít data ze cookiestavu relace nebo s. Získání dat z nového zdroje:

  • Vytvořte třídu, která implementuje IValueProvider.
  • Vytvořte třídu, která implementuje IValueProviderFactory.
  • Zaregistrujte třídu továrny v Program.cssouboru .

Ukázka obsahuje zprostředkovatele hodnot a příklad továrny , který získává hodnoty z cookies. Registrace továren zprostředkovatele vlastních hodnot v Program.cs:

builder.Services.AddControllers(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});

Předchozí kód vloží vlastního zprostředkovatele hodnot za všechny předdefinované zprostředkovatele hodnot. Pokud chcete, aby byl první v seznamu, volejte Insert(0, new CookieValueProviderFactory()) místo Add.

Žádný zdroj vlastnosti modelu

Ve výchozím nastavení se chyba stavu modelu nevytvořila, pokud pro vlastnost modelu nebyla nalezena žádná hodnota. Vlastnost je nastavena na hodnotu null nebo výchozí hodnotu:

  • Jednoduché typy s možnou hodnotou null jsou nastaveny na null.
  • Typy hodnot, které nemají hodnotu null, jsou nastaveny na default(T). Například parametr int id je nastavený na hodnotu 0.
  • Pro komplexní typy vytvoří vazba modelu instanci pomocí výchozího konstruktoru bez nastavení vlastností.
  • Pole jsou nastavena na Array.Empty<T>(), s výjimkou toho, že byte[] pole jsou nastavena na null.

Pokud by měl být stav modelu neplatný, pokud se v polích formuláře pro vlastnost modelu nenajde nic, použijte [BindRequired] atribut.

Všimněte si, že toto [BindRequired] chování se vztahuje na vazbu modelu z publikovaných dat formuláře, nikoli na JSdata ON nebo XML v textu požadavku. Základní data požadavku se zpracovávají vstupními formátovacími moduly.

Chyby převodu typů

Pokud se zdroj najde, ale nedá se převést na cílový typ, stav modelu se označí jako neplatný. Cílový parametr nebo vlastnost je nastaven na hodnotu null nebo výchozí hodnotu, jak je uvedeno v předchozí části.

V kontroleru rozhraní API, který má [ApiController] atribut, způsobí neplatný stav modelu automatickou odpověď HTTP 400.

Razor Na stránce znovu zobrazíte stránku s chybovou zprávou:

public IActionResult OnPost()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    // ...

    return RedirectToPage("./Index");
}

Když se stránka znovu zobrazí předchozím kódem, neplatný vstup se v poli formuláře nezobrazí. Důvodem je to, že vlastnost modelu byla nastavena na hodnotu null nebo výchozí hodnotu. Neplatný vstup se zobrazí v chybové zprávě. Pokud chcete znovu zobrazit špatná data v poli formuláře, zvažte ruční vytvoření vlastnosti modelu řetězec a převod dat ručně.

Stejná strategie se doporučuje, pokud nechcete, aby chyby převodu typů způsoboval chyby stavu modelu. V takovém případě vytvořte vlastnost modelu řetězec.

Jednoduché typy

Mezi jednoduché typy, které může binder modelu převést zdrojové řetězce, patří následující:

Komplexní typy

Komplexní typ musí mít veřejný výchozí konstruktor a veřejné zapisovatelné vlastnosti pro vazbu. Pokud dojde k vazbě modelu, vytvoří se instance třídy pomocí veřejného výchozího konstruktoru.

Pro každou vlastnost komplexního typu hledá vazba modelu zdroje pro vzor názvůprefix.property_name. Pokud se nic nenajde, hledá jenom property_name bez předpony. Rozhodnutí o použití dotazu není provedeno pro každou vlastnost. Například s dotazem obsahujícím ?Instructor.Id=100&Name=foo, vázané na metodu OnGet(Instructor instructor), výsledný objekt typu Instructor obsahuje:

  • Id nastaveno na 100.
  • Name nastaveno na null. Vazba modelu očekává Instructor.Name , protože Instructor.Id byla použita v předchozím parametru dotazu.

Pro vazbu k parametru je předpona názvem parametru. Pro vazbu na PageModel veřejnou vlastnost je předpona názvem veřejné vlastnosti. Některé atributy mají Prefix vlastnost, která umožňuje přepsat výchozí použití parametru nebo názvu vlastnosti.

Předpokládejme například, že komplexní typ je následující Instructor třída:

public class Instructor
{
    public int ID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

Prefix = název parametru

Pokud je model, který má být vázán, parametr s názvem instructorToUpdate:

public IActionResult OnPost(int? id, Instructor instructorToUpdate)

Vazba modelu začíná hledáním zdrojů klíče instructorToUpdate.ID. Pokud ho nenajdete, vyhledá ID se bez předpony.

Předpona = název vlastnosti

Pokud je model, který má být vázán, vlastnost s názvem Instructor kontroleru nebo PageModel třídy:

[BindProperty]
public Instructor Instructor { get; set; }

Vazba modelu začíná hledáním zdrojů klíče Instructor.ID. Pokud ho nenajdete, vyhledá ID se bez předpony.

Vlastní předpona

Pokud je model, který má být vázán, parametr pojmenovaný instructorToUpdate a Bind atribut určuje Instructor jako předponu:

public IActionResult OnPost(
    int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)

Vazba modelu začíná hledáním zdrojů klíče Instructor.ID. Pokud ho nenajdete, vyhledá ID se bez předpony.

Atributy pro cíle komplexního typu

Pro řízení vazby modelu složitých typů je k dispozici několik předdefinovaných atributů:

Upozornění

Tyto atributy ovlivňují vazbu modelu při publikování dat formuláře jako zdroj hodnot. Nemají vliv na vstupní formátovací moduly, které proces publikoval JStělo požadavků ON a XML. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.

Atribut [Bind]

Lze použít u třídy nebo parametru metody. Určuje, které vlastnosti modelu by měly být zahrnuty do vazby modelu. [Bind]nemá vliv na vstupní formátovací moduly.

V následujícím příkladu Instructor jsou při volání jakékoli obslužné rutiny nebo metody akce vázány pouze zadané vlastnosti modelu:

[Bind("LastName,FirstMidName,HireDate")]
public class Instructor

V následujícím příkladu Instructor jsou při volání metody vázány OnPost pouze zadané vlastnosti modelu:

[HttpPost]
public IActionResult OnPost(
    [Bind("LastName,FirstMidName,HireDate")] Instructor instructor)

Atribut [Bind] lze použít k ochraně před nadměrném umístěním ve scénářích vytváření . Ve scénářích úprav nefunguje dobře, protože vyloučené vlastnosti jsou nastaveny na hodnotu null nebo výchozí hodnotu místo toho, aby zůstaly beze změny. Pro ochranu proti nadměrnému umístění se místo atributu [Bind] doporučuje zobrazit modely. Další informace najdete v tématu Poznámky k zabezpečení týkající se nadměrného umístění.

Atribut [ModelBinder]

ModelBinderAttribute lze použít u typů, vlastností nebo parametrů. Umožňuje určit typ pořadače modelu, který se používá k vytvoření vazby konkrétní instance nebo typu. Příklad:

[HttpPost]
public IActionResult OnPost(
    [ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)

Atribut [ModelBinder] lze také použít ke změně názvu vlastnosti nebo parametru při vazbě modelu:

public class Instructor
{
    [ModelBinder(Name = "instructor_id")]
    public string Id { get; set; }

    // ...
}

Atribut [BindRequired]

Lze použít pouze u vlastností modelu, nikoli u parametrů metody. Způsobí, že vazba modelu přidá chybu stavu modelu, pokud nelze vytvořit vazbu pro vlastnost modelu. Tady je příklad:

public class InstructorBindRequired
{
    // ...

    [BindRequired]
    public DateTime HireDate { get; set; }
}

Projděte si také diskuzi o atributu [Required] v ověření modelu.

Atribut [BindNever]

Lze použít u vlastnosti nebo typu. Zabrání vazbě modelu v nastavení vlastnosti modelu. Při použití na typ systém vazby modelu vylučuje všechny vlastnosti, které typ definuje. Tady je příklad:

public class InstructorBindNever
{
    [BindNever]
    public int Id { get; set; }

    // ...
}

Kolekce

U cílů, které jsou kolekcemi jednoduchých typů, hledá vazby modelu shody s parameter_name nebo property_name. Pokud se nenajde žádná shoda, vyhledá jeden z podporovaných formátů bez předpony. Příklad:

  • Předpokládejme, že parametr, který má být vázán, je pole s názvem selectedCourses:

    public IActionResult OnPost(int? id, int[] selectedCourses)
    
  • Data řetězce formuláře nebo dotazu můžou být v jednom z následujících formátů:

    selectedCourses=1050&selectedCourses=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    

Vyhněte se vazbě parametru nebo vlastnosti pojmenované index nebo Index pokud se nachází vedle hodnoty kolekce. Vazby modelu se pokusí použít index jako index kolekce, což může vést k nesprávné vazbě. Představte si například následující akci:

public IActionResult Post(string index, List<Product> products)

V předchozím kódu index se parametr řetězce dotazu sváže s parametrem index metody a také slouží k vytvoření vazby kolekce produktů. Přejmenování parametru index nebo použití atributu vazby modelu ke konfiguraci vazby zabrání tomuto problému:

public IActionResult Post(string productIndex, List<Product> products)
selectedCourses[]=1050&selectedCourses[]=2000
  • U všech předchozích ukázkových formátů předá vazba modelu matici dvou položek parametru selectedCourses :

    • selectedCourses[0]=1050
    • selectedCourses[1]=2000

    Formáty dat, které používají čísla dolního indexu (... [0] ... [1] ...) musí zajistit, aby byly číslovány postupně od nuly. Pokud jsou v číslování dolního indexu nějaké mezery, budou všechny položky po mezerách ignorovány. Pokud jsou například dolní indexy 0 a 2 místo 0 a 1, druhá položka se ignoruje.

Slovníky

U Dictionary cílů hledá vazby modelu shody s parameter_name nebo property_name. Pokud se nenajde žádná shoda, vyhledá jeden z podporovaných formátů bez předpony. Příklad:

  • Předpokládejme, že cílový parametr je pojmenovaný Dictionary<int, string>selectedCourses:

    public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
    
  • Publikovaných dat formuláře nebo řetězce dotazu může vypadat jako jeden z následujících příkladů:

    selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics
    
    [1050]=Chemistry&selectedCourses[2000]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Pro všechny předchozí ukázkové formáty předá vazba modelu slovník dvou položek parametru selectedCourses :

    • selectedCourses["1050"]="Chemie"
    • selectedCourses["2000"]="Ekonomika"

Vazby konstruktoru a typy záznamů

Vazba modelu vyžaduje, aby komplexní typy měly konstruktor bez parametrů. System.Text.Json Formátovací moduly pro vstup i Newtonsoft.Json na základě podporují deserializaci tříd, které nemají konstruktor bez parametrů.

Typy záznamů představují skvělý způsob, jak stručně znázorňovat data v síti. ASP.NET Core podporuje vazby modelu a ověřování typů záznamů pomocí jednoho konstruktoru:

public record Person(
    [Required] string Name, [Range(0, 150)] int Age, [BindNever] int Id);

public class PersonController
{
    public IActionResult Index() => View();

    [HttpPost]
    public IActionResult Index(Person person)
    {
        // ...
    }
}

Person/Index.cshtml:

@model Person

Name: <input asp-for="Name" />
<br />
Age: <input asp-for="Age" />

Při ověřování typů záznamů modul runtime vyhledá metadata vazby a ověřování, a to konkrétně u parametrů, nikoli u vlastností.

Architektura umožňuje vazby a ověřování typů záznamů:

public record Person([Required] string Name, [Range(0, 100)] int Age);

Aby předchozí práce fungovala, musí typ:

  • Buďte typem záznamu.
  • Mít přesně jeden veřejný konstruktor.
  • Obsahují parametry, které mají vlastnost se stejným názvem a typem. Názvy se nesmí lišit podle písmen.

PoCOs bez konstruktorů bez parametrů

Funkce POCO, které nemají konstruktory bez parametrů, nemohou být vázány.

Výsledkem následujícího kódu je výjimka, která říká, že typ musí mít konstruktor bez parametrů:

public class Person(string Name)

public record Person([Required] string Name, [Range(0, 100)] int Age)
{
    public Person(string Name) : this (Name, 0);
}

Typy záznamů s ručně vytvořenými konstruktory

Typy záznamů s ručně vytvořenými konstruktory, které vypadají jako primární konstruktory

public record Person
{
    public Person([Required] string Name, [Range(0, 100)] int Age)
        => (this.Name, this.Age) = (Name, Age);

    public string Name { get; set; }
    public int Age { get; set; }
}

Typy záznamů, ověřování a vazba metadata

Pro typy záznamů se používají metadata ověřování a vazby parametrů. Všechna metadata vlastností se ignorují.

public record Person (string Name, int Age)
{
   [BindProperty(Name = "SomeName")] // This does not get used
   [Required] // This does not get used
   public string Name { get; init; }
}

Ověřování a metadata

Ověřování používá metadata parametru, ale používá vlastnost ke čtení hodnoty. V běžném případě s primárními konstruktory by tyto dva byly identické. Existují však způsoby, jak ji porazit:

public record Person([Required] string Name)
{
    private readonly string _name;

    // The following property is never null.
    // However this object could have been constructed as "new Person(null)".
    public string Name { get; init => _name = value ?? string.Empty; }
}

TryUpdateModel neaktualizuje parametry u typu záznamu.

public record Person(string Name)
{
    public int Age { get; set; }
}

var person = new Person("initial-name");
TryUpdateModel(person, ...);

V tomto případě se MVC nebude pokoušet o vazbu Name znovu. Age Je však možné aktualizovat

Chování globalizace vazby modelu směruje data a řetězce dotazů

Zprostředkovatel hodnot trasy ASP.NET Core a poskytovatel řetězcových hodnot dotazu:

  • Zachází s hodnotami jako s invariantní jazykovou verzí.
  • Očekáváme, že adresy URL jsou invariantní pro jazykovou verzi.

Naproti tomu hodnoty pocházející z dat formuláře procházejí převodem citlivým na jazykovou verzi. To je návrh tak, aby adresy URL byly sdíleny napříč národními prostředími.

Pokud chcete, aby ASP.NET zprostředkovatele hodnot tras core a zprostředkovatele hodnot řetězce dotazu prošla převodem citlivým na jazykovou verzi:

public class CultureQueryStringValueProviderFactory : IValueProviderFactory
{
    public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
    {
        _ = context ?? throw new ArgumentNullException(nameof(context));

        var query = context.ActionContext.HttpContext.Request.Query;
        if (query?.Count > 0)
        {
            context.ValueProviders.Add(
                new QueryStringValueProvider(
                    BindingSource.Query,
                    query,
                    CultureInfo.CurrentCulture));
        }

        return Task.CompletedTask;
    }
}
builder.Services.AddControllers(options =>
{
    var index = options.ValueProviderFactories.IndexOf(
        options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>()
            .Single());

    options.ValueProviderFactories[index] =
        new CultureQueryStringValueProviderFactory();
});

Speciální datové typy

Existují některé speciální datové typy, které můžou zpracovat vazby modelu.

IFormFile a IFormFileCollection

Nahraný soubor zahrnutý v požadavku HTTP. Podporuje se IEnumerable<IFormFile> také více souborů.

Cancellationtoken

Akce můžou volitelně vytvořit vazbu CancellationToken jako parametr. Tím se vytvoří vazba RequestAborted , která signalizuje, že dojde k přerušení připojení, které je základem požadavku HTTP. Akce můžou tento parametr použít k zrušení dlouhotrvajících asynchronních operací, které se spouští jako součást akcí kontroleru.

FormCollection

Slouží k načtení všech hodnot z publikovaných dat formuláře.

Vstupní formátovací moduly

Data v textu požadavku můžou být v JSON, XML nebo jiném formátu. K analýze těchto dat používá vazba modelu vstupní formátovač , který je nakonfigurovaný pro zpracování konkrétního typu obsahu. Ve výchozím nastavení ASP.NET Core zahrnuje JSvstupní formátovací moduly založené na on pro zpracování JSdat ON. Můžete přidat další formátovací moduly pro jiné typy obsahu.

ASP.NET Core vybere vstupní formátovací moduly na základě atributu Spotřebovávat . Pokud neexistuje žádný atribut, použije hlavičku Content-Type.

Použití předdefinovaných formátovacích souborů XML:

Přizpůsobení vazby modelu pomocí vstupních formátovacích nástrojů

Vstupní formátovací modul přebírá plnou odpovědnost za čtení dat z textu požadavku. Chcete-li tento proces přizpůsobit, nakonfigurujte rozhraní API používaná vstupním formátovačem. Tato část popisuje, jak přizpůsobit System.Text.Jsonformátovací modul založený na vstupu, aby porozuměl vlastnímu typu s názvem ObjectId.

Zvažte následující model, který obsahuje vlastní ObjectId vlastnost s názvem Id:

public class InstructorObjectId
{
    [Required]
    public ObjectId ObjectId { get; set; } = null!;
}

Chcete-li přizpůsobit proces vazby modelu při použití System.Text.Json, vytvořte třídu odvozenou z JsonConverter<T>:

internal class ObjectIdConverter : JsonConverter<ObjectId>
{
    public override ObjectId Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => new(JsonSerializer.Deserialize<int>(ref reader, options));

    public override void Write(
        Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
        => writer.WriteNumberValue(value.Id);
}

Chcete-li použít vlastní převaděč, použijte atribut JsonConverterAttribute na typ. V následujícím příkladu ObjectId je typ nakonfigurován ObjectIdConverter jako vlastní převaděč:

[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);

Další informace najdete v tématu Jak psát vlastní převaděče.

Vyloučení zadaných typů z vazby modelu

Chování vazeb modelu a ověřovacích systémů je řízeno ModelMetadata. Můžete přizpůsobit ModelMetadata přidáním zprostředkovatele podrobností do MvcOptions.ModelMetadataDetailsProviders. Předdefinované zprostředkovatelé podrobností jsou k dispozici pro zakázání vazby modelu nebo ověření pro zadané typy.

Pokud chcete zakázat vazbu modelu u všech modelů zadaného typu, přidejte do ExcludeBindingMetadataProviderProgram.cssouboru . Pokud chcete například zakázat vazbu modelu u všech modelů typu System.Version:

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.ModelMetadataDetailsProviders.Add(
            new ExcludeBindingMetadataProvider(typeof(Version)));
        options.ModelMetadataDetailsProviders.Add(
            new SuppressChildValidationMetadataProvider(typeof(Guid)));
    });

Chcete-li zakázat ověřování vlastností zadaného typu, přidejte do SuppressChildValidationMetadataProviderProgram.cssouboru . Pokud chcete například zakázat ověřování u vlastností typu System.Guid:

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.ModelMetadataDetailsProviders.Add(
            new ExcludeBindingMetadataProvider(typeof(Version)));
        options.ModelMetadataDetailsProviders.Add(
            new SuppressChildValidationMetadataProvider(typeof(Guid)));
    });

Vlastní pořadače modelů

Vazby modelu můžete rozšířit tak, že napíšete vlastní vazbu modelu a pomocí atributu [ModelBinder] ji vyberete pro daný cíl. Přečtěte si další informace o vazbě vlastního modelu.

Ruční vazba modelu

Vazbu modelu je možné ručně vyvolat pomocí TryUpdateModelAsync metody. Metoda je definována v obou ControllerBasePageModel třídách. Přetížení metody umožňují zadat předponu a zprostředkovatele hodnot, který se má použít. Metoda vrátí false , pokud vazba modelu selže. Tady je příklad:

if (await TryUpdateModelAsync(
    newInstructor,
    "Instructor",
    x => x.Name, x => x.HireDate!))
{
    _instructorStore.Add(newInstructor);
    return RedirectToPage("./Index");
}

return Page();

TryUpdateModelAsync používá zprostředkovatele hodnot k získání dat z textu formuláře, řetězce dotazu a směrování dat. TryUpdateModelAsync obvykle:

  • Používá se s aplikacemi Razor Pages a MVC pomocí kontrolerů a zobrazení, aby se zabránilo nadměrnému publikování.
  • Nepoužívá se s webovým rozhraním API, pokud není spotřebováno z dat formuláře, řetězců dotazů a směrovacích dat. Koncové body webového rozhraní API, které využívají JSfunkci ON, používají k deserializaci textu požadavku do objektu.

Další informace naleznete v tématu TryUpdateModelAsync.

Atribut [FromServices]

Název tohoto atributu se řídí vzorem atributů vazby modelu, které určují zdroj dat. Nejedná se ale o vazbu dat od zprostředkovatele hodnot. Získá instanci typu z kontejneru injektáže závislostí . Jejím účelem je poskytnout alternativu k injektáži konstruktoru, pokud potřebujete službu pouze v případě, že je volána konkrétní metoda.

Pokud instance typu není zaregistrovaná v kontejneru injektáže závislostí, aplikace vyvolá výjimku při pokusu o vytvoření vazby parametru. Pokud chcete parametr nastavit jako volitelný, použijte jeden z následujících přístupů:

  • Nastavte parametr jako null.
  • Nastavte výchozí hodnotu parametru.

V případě parametrů s možnou hodnotou null se ujistěte, že parametr není null před přístupem k němu.

Tento článek vysvětluje, co je vazba modelu, jak funguje a jak přizpůsobit jeho chování.

Zobrazení nebo stažení vzorového kódu (postup stažení)

Co je vazba modelu

Kontrolery a Razor stránky pracují s daty pocházejícími z požadavků HTTP. Například směrovací data můžou poskytnout klíč záznamu a publikované pole formuláře můžou poskytovat hodnoty vlastností modelu. Psaní kódu pro načtení každé z těchto hodnot a jejich převod z řetězců na typy .NET by bylo zdlouhavé a náchylné k chybám. Vazba modelu tento proces automatizuje. Systém vazeb modelu:

  • Načte data z různých zdrojů, jako jsou směrovací data, pole formulářů a řetězce dotazu.
  • Poskytuje data kontrolerů a Razor stránek v parametrech metody a veřejných vlastnostech.
  • Převede řetězcová data na typy .NET.
  • Aktualizuje vlastnosti komplexních typů.

Příklad

Předpokládejme, že máte následující metodu akce:

[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)

Aplikace obdrží požadavek s touto adresou URL:

http://contoso.com/api/pets/2?DogsOnly=true

Vazba modelu prochází následujícími kroky poté, co systém směrování vybere metodu akce:

  • Vyhledá první parametr GetById, celé číslo s názvem id.
  • Vyhledá dostupné zdroje v požadavku HTTP a vyhledá id hodnotu =2 ve směrovacích datech.
  • Převede řetězec "2" na celé číslo 2.
  • Vyhledá další parametr logické hodnoty GetByIds názvem dogsOnly.
  • Projde zdroje a najde v řetězci dotazu "DogsOnly=true". Porovnávání názvů nerozlišuje malá a velká písmena.
  • Převede řetězec "true" na logickou truehodnotu .

Architektura pak volá metodu GetById , předá parametru 2 id a true parametru dogsOnly .

V předchozím příkladu jsou cíle vazby modelu parametry metody, které jsou jednoduché typy. Cíle mohou být také vlastnosti komplexního typu. Po úspěšném vázaní každé vlastnosti dojde k ověření modelu pro tuto vlastnost. Záznam dat, která jsou svázaná s modelem, a všechny chyby vazby nebo ověření, jsou uloženy v ControllerBase.ModelState nebo PageModel.ModelState. Pokud chcete zjistit, jestli byl tento proces úspěšný, aplikace zkontroluje příznak ModelState.IsValid .

Targets

Vazba modelu se pokouší najít hodnoty pro následující typy cílů:

  • Parametry metody akce kontroleru, do které je požadavek směrován.
  • Razor Parametry metody obslužné rutiny Pages, do které je požadavek směrován.
  • Veřejné vlastnosti kontroleru nebo PageModel třídy, pokud jsou zadány atributy.

Atribut [BindProperty]

Lze použít na veřejnou vlastnost kontroleru nebo PageModel třídy způsobit vazbu modelu cílit na tuto vlastnost:

public class EditModel : InstructorsPageModel
{
    [BindProperty]
    public Instructor Instructor { get; set; }

Atribut [BindProperties]

K dispozici v ASP.NET Core 2.1 a novějších verzích. Lze použít u kontroleru nebo PageModel třídy, aby bylo možné určit vazbu modelu tak, aby cílila na všechny veřejné vlastnosti třídy:

[BindProperties(SupportsGet = true)]
public class CreateModel : InstructorsPageModel
{
    public Instructor Instructor { get; set; }

Vazba modelu pro požadavky HTTP GET

Ve výchozím nastavení nejsou vlastnosti vázané na požadavky HTTP GET. Obvykle je vše, co potřebujete pro požadavek GET, parametr ID záznamu. ID záznamu slouží k vyhledání položky v databázi. Proto není nutné vytvořit vazbu vlastnosti, která obsahuje instanci modelu. Ve scénářích, kde chcete, aby vlastnosti vázané na data z požadavků GET, nastavte SupportsGet vlastnost na true:

[BindProperty(Name = "ai_user", SupportsGet = true)]
public string ApplicationInsightsCookie { get; set; }

zdroje

Vazba modelu ve výchozím nastavení získává data ve formě párů klíč-hodnota z následujících zdrojů v požadavku HTTP:

  1. Pole formuláře
  2. Text požadavku (pro kontrolery, které mají atribut [ApiController].)
  3. Směrování dat
  4. Parametry řetězce dotazu
  5. Nahrané soubory

Pro každý cílový parametr nebo vlastnost jsou zdroje prohledávány v pořadí uvedeném v předchozím seznamu. Existuje několik výjimek:

  • Směrovat data a řetězcové hodnoty dotazu se používají pouze pro jednoduché typy.
  • Nahrané soubory jsou vázány pouze na cílové typy, které implementují IFormFile nebo IEnumerable<IFormFile>.

Pokud výchozí zdroj není správný, zadejte zdroj jedním z následujících atributů:

Tyto atributy:

  • Jsou přidány do vlastností modelu jednotlivě (ne do třídy modelu), jako v následujícím příkladu:

    public class Instructor
    {
        public int ID { get; set; }
    
        [FromQuery(Name = "Note")]
        public string NoteFromQueryString { get; set; }
    
  • Volitelně přijměte hodnotu názvu modelu v konstruktoru. Tato možnost je k dispozici v případě, že název vlastnosti neodpovídá hodnotě v požadavku. Například hodnota v požadavku může být hlavička s pomlčkam v názvu, jako v následujícím příkladu:

    public void OnGet([FromHeader(Name = "Accept-Language")] string language)
    

Atribut [FromBody]

[FromBody] Použijte atribut na parametr k naplnění jeho vlastností z textu požadavku HTTP. Modul runtime ASP.NET Core deleguje odpovědnost za čtení textu na vstupní formátovač. Formátovací moduly vstupu jsou vysvětleny dále v tomto článku.

Při [FromBody] použití u komplexního parametru typu se všechny atributy zdroje vazby použité na jeho vlastnosti ignorují. Například následující Create akce určuje, že se jeho pet parametr naplní z textu:

public ActionResult<Pet> Create([FromBody] Pet pet)

Třída Pet určuje, že jeho Breed vlastnost je naplněna z parametru řetězce dotazu:

public class Pet
{
    public string Name { get; set; }

    [FromQuery] // Attribute is ignored.
    public string Breed { get; set; }
}

V předchozím příkladu:

  • Atribut [FromQuery] se ignoruje.
  • Vlastnost Breed není naplněna parametrem řetězce dotazu.

Vstupní formátovací moduly čtou jenom tělo a nerozumí atributům zdroje vazeb. Pokud je v textu nalezena vhodná hodnota, tato hodnota se použije k naplnění Breed vlastnosti.

Nevztahuje se [FromBody] na více než jeden parametr na metodu akce. Jakmile datový proud požadavku přečte vstupní formátovací modul, už není k dispozici ke čtení pro vazbu dalších [FromBody] parametrů.

Další zdroje

Zdrojová data jsou poskytována systému vazby modelu poskytovateli hodnot. Můžete napsat a zaregistrovat vlastní zprostředkovatele hodnot, kteří získávají data pro vazbu modelu z jiných zdrojů. Můžete například chtít data ze cookiestavu relace nebo s. Získání dat z nového zdroje:

  • Vytvořte třídu, která implementuje IValueProvider.
  • Vytvořte třídu, která implementuje IValueProviderFactory.
  • Zaregistrujte třídu továrny v Startup.ConfigureServicessouboru .

Ukázková aplikace obsahuje zprostředkovatele hodnot a příklad továrny , který získá hodnoty z cookies. Tady je registrační kód v Startup.ConfigureServices:

services.AddRazorPages()
    .AddMvcOptions(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
    options.ModelMetadataDetailsProviders.Add(
        new ExcludeBindingMetadataProvider(typeof(System.Version)));
    options.ModelMetadataDetailsProviders.Add(
        new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters();

Zobrazený kód umístí vlastního zprostředkovatele hodnot za všechny předdefinované zprostředkovatele hodnot. Pokud chcete, aby byl první v seznamu, volejte Insert(0, new CookieValueProviderFactory()) místo Add.

Žádný zdroj vlastnosti modelu

Ve výchozím nastavení se chyba stavu modelu nevytvořila, pokud pro vlastnost modelu nebyla nalezena žádná hodnota. Vlastnost je nastavena na hodnotu null nebo výchozí hodnotu:

  • Jednoduché typy s možnou hodnotou null jsou nastaveny na null.
  • Typy hodnot, které nemají hodnotu null, jsou nastaveny na default(T). Například parametr int id je nastavený na hodnotu 0.
  • Pro komplexní typy vytvoří vazba modelu instanci pomocí výchozího konstruktoru bez nastavení vlastností.
  • Pole jsou nastavena na Array.Empty<T>(), s výjimkou toho, že byte[] pole jsou nastavena na null.

Pokud by měl být stav modelu neplatný, pokud se v polích formuláře pro vlastnost modelu nenajde nic, použijte [BindRequired] atribut.

Všimněte si, že toto [BindRequired] chování se vztahuje na vazbu modelu z publikovaných dat formuláře, nikoli na JSdata ON nebo XML v textu požadavku. Základní data požadavku se zpracovávají vstupními formátovacími moduly.

Chyby převodu typů

Pokud se zdroj najde, ale nedá se převést na cílový typ, stav modelu se označí jako neplatný. Cílový parametr nebo vlastnost je nastaven na hodnotu null nebo výchozí hodnotu, jak je uvedeno v předchozí části.

V kontroleru rozhraní API, který má [ApiController] atribut, způsobí neplatný stav modelu automatickou odpověď HTTP 400.

Razor Na stránce znovu zobrazíte stránku s chybovou zprávou:

public IActionResult OnPost()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _instructorsInMemoryStore.Add(Instructor);
    return RedirectToPage("./Index");
}

Ověření na straně klienta zachytí většinu chybných dat, která by jinak byla odeslána Razor do formuláře Stránky. Toto ověření znesnadňuje aktivaci předchozího zvýrazněného kódu. Ukázková aplikace obsahuje tlačítko Odeslat s neplatným datem , které vloží špatná data do pole Datum přijetí a odešle formulář. Toto tlačítko ukazuje, jak kód pro opětovné zobrazení stránky funguje, když dojde k chybám převodu dat.

Při opětovném zobrazení stránky předchozím kódem se v poli formuláře nezobrazí neplatný vstup. Důvodem je to, že vlastnost modelu byla nastavena na hodnotu null nebo výchozí hodnotu. Neplatný vstup se zobrazí v chybové zprávě. Pokud ale chcete znovu zobrazit špatná data v poli formuláře, zvažte ruční vytvoření vlastnosti modelu řetězec a provedení převodu dat ručně.

Stejná strategie se doporučuje, pokud nechcete, aby chyby převodu typů způsoboval chyby stavu modelu. V takovém případě vytvořte vlastnost modelu řetězec.

Jednoduché typy

Mezi jednoduché typy, které může binder modelu převést zdrojové řetězce, patří následující:

Komplexní typy

Komplexní typ musí mít veřejný výchozí konstruktor a veřejné zapisovatelné vlastnosti pro vazbu. Pokud dojde k vazbě modelu, vytvoří se instance třídy pomocí veřejného výchozího konstruktoru.

Pro každou vlastnost komplexního typu hledá vazba modelu zdroje pro vzor názvů prefix.property_name. Pokud se nic nenajde, hledá jenom property_name bez předpony.

Pro vazbu k parametru je předpona názvem parametru. Pro vazbu na PageModel veřejnou vlastnost je předpona názvem veřejné vlastnosti. Některé atributy mají Prefix vlastnost, která umožňuje přepsat výchozí použití parametru nebo názvu vlastnosti.

Předpokládejme například, že komplexní typ je následující Instructor třída:

public class Instructor
{
    public int ID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
}

Prefix = název parametru

Pokud je model, který má být vázán, parametr s názvem instructorToUpdate:

public IActionResult OnPost(int? id, Instructor instructorToUpdate)

Vazba modelu začíná hledáním zdrojů klíče instructorToUpdate.ID. Pokud ho nenajdete, vyhledá ID se bez předpony.

Předpona = název vlastnosti

Pokud je model, který má být vázán, vlastnost s názvem Instructor kontroleru nebo PageModel třídy:

[BindProperty]
public Instructor Instructor { get; set; }

Vazba modelu začíná hledáním zdrojů klíče Instructor.ID. Pokud ho nenajdete, vyhledá ID se bez předpony.

Vlastní předpona

Pokud je model, který má být vázán, parametr pojmenovaný instructorToUpdate a Bind atribut určuje Instructor jako předponu:

public IActionResult OnPost(
    int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)

Vazba modelu začíná hledáním zdrojů klíče Instructor.ID. Pokud ho nenajdete, vyhledá ID se bez předpony.

Atributy pro cíle komplexního typu

Pro řízení vazby modelu složitých typů je k dispozici několik předdefinovaných atributů:

  • [Bind]
  • [BindRequired]
  • [BindNever]

Upozornění

Tyto atributy ovlivňují vazbu modelu při publikování dat formuláře jako zdroj hodnot. Nemají vliv na vstupní formátovací moduly, které proces publikoval JStělo požadavků ON a XML. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.

Atribut [Bind]

Lze použít u třídy nebo parametru metody. Určuje, které vlastnosti modelu by měly být zahrnuty do vazby modelu. [Bind]nemá vliv na vstupní formátovací moduly.

V následujícím příkladu Instructor jsou při volání jakékoli obslužné rutiny nebo metody akce vázány pouze zadané vlastnosti modelu:

[Bind("LastName,FirstMidName,HireDate")]
public class Instructor

V následujícím příkladu Instructor jsou při volání metody vázány OnPost pouze zadané vlastnosti modelu:

[HttpPost]
public IActionResult OnPost([Bind("LastName,FirstMidName,HireDate")] Instructor instructor)

Atribut [Bind] lze použít k ochraně před nadměrném umístěním ve scénářích vytváření . Ve scénářích úprav nefunguje dobře, protože vyloučené vlastnosti jsou nastaveny na hodnotu null nebo výchozí hodnotu místo toho, aby zůstaly beze změny. Pro ochranu proti nadměrnému umístění se místo atributu [Bind] doporučuje zobrazit modely. Další informace najdete v tématu Poznámky k zabezpečení týkající se nadměrného umístění.

Atribut [ModelBinder]

ModelBinderAttribute lze použít u typů, vlastností nebo parametrů. Umožňuje určit typ pořadače modelu, který se používá k vytvoření vazby konkrétní instance nebo typu. Příklad:

[HttpPost]
public IActionResult OnPost([ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)

Atribut [ModelBinder] lze také použít ke změně názvu vlastnosti nebo parametru při vazbě modelu:

public class Instructor
{
    [ModelBinder(Name = "instructor_id")]
    public string Id { get; set; }

    public string Name { get; set; }
}

Atribut [BindRequired]

Lze použít pouze u vlastností modelu, nikoli na parametry metody. Způsobí, že vazba modelu přidá chybu stavu modelu, pokud vazba nemůže nastat pro vlastnost modelu. Tady je příklad:

public class InstructorWithCollection
{
    public int ID { get; set; }

    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    [Display(Name = "Hire Date")]
    [BindRequired]
    public DateTime HireDate { get; set; }

Projděte si také diskuzi o atributu [Required] v ověření modelu.

Atribut [BindNever]

Lze použít pouze u vlastností modelu, nikoli na parametry metody. Zabrání vazbě modelu v nastavení vlastnosti modelu. Tady je příklad:

public class InstructorWithDictionary
{
    [BindNever]
    public int ID { get; set; }

Kolekce

U cílů, které jsou kolekcemi jednoduchých typů, vazba modelu hledá shody parameter_name neboproperty_name. Pokud se nenajde žádná shoda, vyhledá jeden z podporovaných formátů bez předpony. Příklad:

  • Předpokládejme, že parametr, který má být vázán, je pole s názvem selectedCourses:

    public IActionResult OnPost(int? id, int[] selectedCourses)
    
  • Data řetězce formuláře nebo dotazu můžou být v jednom z následujících formátů:

    selectedCourses=1050&selectedCourses=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    

    Vyhněte se vazbě parametru nebo vlastnosti s názvem index nebo Index pokud sousedí s hodnotou kolekce. Vazby modelu se pokusí použít index jako index pro kolekci, což může vést k nesprávné vazbě. Představte si například následující akci:

    public IActionResult Post(string index, List<Product> products)
    

    V předchozím kódu index se parametr řetězce dotazu sváže s parametrem index metody a používá se také k vytvoření vazby kolekce produktů. Přejmenování parametru index nebo použití atributu vazby modelu ke konfiguraci vazby zabrání tomuto problému:

    public IActionResult Post(string productIndex, List<Product> products)
    
  • Následující formát je podporován pouze v datech formuláře:

    selectedCourses[]=1050&selectedCourses[]=2000
    
  • Pro všechny předchozí ukázkové formáty předá vazba modelu do parametru selectedCourses pole dvou položek:

    • selectedCourses[0]=1050
    • selectedCourses[1]=2000

    Formáty dat, které používají čísla dolního indexu (... [0] ... [1] ...) musí zajistit, aby byly očíslovány postupně počínaje nulou. Pokud jsou v číslování dolního indexu nějaké mezery, budou všechny položky po mezerě ignorovány. Pokud jsou například dolní indexy 0 a 2 místo 0 a 1, druhá položka se ignoruje.

Slovníky

V případě Dictionary cílů hledá vazby modelu shody parameter_name neboproperty_name. Pokud se nenajde žádná shoda, vyhledá jeden z podporovaných formátů bez předpony. Příklad:

  • Předpokládejme, že cílový parametr je pojmenovaný Dictionary<int, string>selectedCourses:

    public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
    
  • Publikovaných dat formuláře nebo řetězce dotazu může vypadat jako jeden z následujících příkladů:

    selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics
    
    [1050]=Chemistry&selectedCourses[2000]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Pro všechny předchozí ukázkové formáty předá vazba modelu slovník dvou položek parametru selectedCourses :

    • selectedCourses["1050"]="Chemie"
    • selectedCourses["2000"]="Ekonomika"

Vazby konstruktoru a typy záznamů

Vazba modelu vyžaduje, aby komplexní typy měly konstruktor bez parametrů. Newtonsoft.Json Formátovací System.Text.Json moduly pro zadávání na základě podporují deserializaci tříd, které nemají konstruktor bez parametrů.

Jazyk C# 9 zavádí typy záznamů, což je skvělý způsob, jak stručně znázorňovat data v síti. ASP.NET Core přidává podporu pro vazby modelu a ověřování typů záznamů pomocí jednoho konstruktoru:

public record Person([Required] string Name, [Range(0, 150)] int Age, [BindNever] int Id);

public class PersonController
{
   public IActionResult Index() => View();

   [HttpPost]
   public IActionResult Index(Person person)
   {
       ...
   }
}

Person/Index.cshtml:

@model Person

Name: <input asp-for="Name" />
...
Age: <input asp-for="Age" />

Při ověřování typů záznamů modul runtime vyhledá metadata vazby a ověření, a to konkrétně u parametrů, nikoli u vlastností.

Architektura umožňuje vazby k typům záznamů a jejich ověřování:

public record Person([Required] string Name, [Range(0, 100)] int Age);

Aby předchozí funkce fungovala, musí typ:

  • Buďte typem záznamu.
  • Mít přesně jeden veřejný konstruktor.
  • Obsahují parametry, které mají vlastnost se stejným názvem a typem. Názvy se nesmí lišit podle písmen.

PoCOs bez konstruktorů bez parametrů

PoCOs, které nemají konstruktory bez parametrů, nelze svázat.

Výsledkem následujícího kódu je výjimka, že typ musí mít konstruktor bez parametrů:

public class Person(string Name)

public record Person([Required] string Name, [Range(0, 100)] int Age)
{
   public Person(string Name) : this (Name, 0);
}

Typy záznamů s ručně vytvořenými konstruktory

Typy záznamů s ručně vytvořenými konstruktory, které vypadají jako primární konstruktory

public record Person
{
   public Person([Required] string Name, [Range(0, 100)] int Age) => (this.Name, this.Age) = (Name, Age);

   public string Name { get; set; }
   public int Age { get; set; }
}

Typy záznamů, ověřování a metadata vazeb

Pro typy záznamů se používají metadata ověřování a vazby parametrů. Všechna metadata vlastností se ignorují.

public record Person (string Name, int Age)
{
   [BindProperty(Name = "SomeName")] // This does not get used
   [Required] // This does not get used
   public string Name { get; init; }
}

Ověřování a metadata

Ověřování používá metadata parametru, ale vlastnost používá ke čtení hodnoty. V běžném případě s primárními konstruktory by oba dva byly identické. Existují však způsoby, jak ji porazit:

public record Person([Required] string Name)
{
   private readonly string _name;
   public Name { get; init => _name = value ?? string.Empty; } // Now this property is never null. However this object could have been constructed as `new Person(null);`
}

TryUpdateModel neaktualizuje parametry u typu záznamu

public record Person(string Name)
{
   public int Age { get; set; }
}

var person = new Person("initial-name");
TryUpdateModel(person, ...);

V tomto případě se MVC nebude pokoušet o vytvoření vazby Name znovu. Age Je však možné aktualizovat

Chování globalizace vazby modelu směruje data a řetězce dotazů

Zprostředkovatel hodnoty trasy ASP.NET Core a poskytovatel řetězcových hodnot dotazu:

  • Považuje hodnoty za invariantní jazykovou verzi.
  • Očekává se, že adresy URL jsou invariantní pro jazykovou verzi.

Naproti tomu hodnoty pocházející z dat formuláře procházejí převodem citlivým na jazykovou verzi. To je návrh, aby adresy URL byly sdíleny mezi národními prostředími.

Pokud chcete, aby poskytovatel hodnoty trasy ASP.NET Core a poskytovatel řetězcových hodnot dotazu prošel převodem citlivých na jazykovou verzi:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        var index = options.ValueProviderFactories.IndexOf(
            options.ValueProviderFactories.OfType<QueryStringValueProviderFactory>().Single());
        options.ValueProviderFactories[index] = new CulturedQueryStringValueProviderFactory();
    });
}
public class CulturedQueryStringValueProviderFactory : IValueProviderFactory
{
    public Task CreateValueProviderAsync(ValueProviderFactoryContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var query = context.ActionContext.HttpContext.Request.Query;
        if (query != null && query.Count > 0)
        {
            var valueProvider = new QueryStringValueProvider(
                BindingSource.Query,
                query,
                CultureInfo.CurrentCulture);

            context.ValueProviders.Add(valueProvider);
        }

        return Task.CompletedTask;
    }
}

Speciální datové typy

Existují některé speciální datové typy, které můžou zpracovávat vazby modelu.

IFormFile a IFormFileCollection

Nahraný soubor zahrnutý v požadavku HTTP. Podporuje se IEnumerable<IFormFile> také více souborů.

Cancellationtoken

Akce můžou volitelně svázat CancellationToken jako parametr. To vytvoří vazbu RequestAborted , která signalizuje, že dojde k přerušení připojení souvisejícího s požadavkem HTTP. Akce můžou tento parametr použít k zrušení dlouhotrvajících asynchronních operací, které se spouští jako součást akcí kontroleru.

FormCollection

Slouží k načtení všech hodnot z publikovaných dat formuláře.

Vstupní formátovací moduly

Data v textu požadavku můžou být v JSON, XML nebo jiném formátu. K analýze těchto dat používá vazba modelu vstupní formátovač , který je nakonfigurovaný pro zpracování konkrétního typu obsahu. Ve výchozím nastavení ASP.NET Core zahrnuje JSvstupní formátovací moduly založené na zapnuto pro zpracování JSdat ON. Můžete přidat další formátovací moduly pro jiné typy obsahu.

ASP.NET Core vybere vstupní formátovací moduly na základě atributu Consumes . Pokud neexistuje žádný atribut, použije hlavičku Content-Type.

Použití předdefinovaných formátovacích souborů XML:

  • Microsoft.AspNetCore.Mvc.Formatters.Xml Nainstalujte balíček NuGet.

  • Zavolat Startup.ConfigureServicesAddXmlSerializerFormatters nebo AddXmlDataContractSerializerFormatters.

    services.AddRazorPages()
        .AddMvcOptions(options =>
    {
        options.ValueProviderFactories.Add(new CookieValueProviderFactory());
        options.ModelMetadataDetailsProviders.Add(
            new ExcludeBindingMetadataProvider(typeof(System.Version)));
        options.ModelMetadataDetailsProviders.Add(
            new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
    })
    .AddXmlSerializerFormatters();
    
  • Consumes Použijte atribut na třídy kontroleru nebo metody akce, které by měly očekávat XML v textu požadavku.

    [HttpPost]
    [Consumes("application/xml")]
    public ActionResult<Pet> Create(Pet pet)
    

    Další informace naleznete v tématu Představení serializace XML.

Přizpůsobení vazby modelu pomocí vstupních formátovacích nástrojů

Vstupní formátovací modul přebírá plnou odpovědnost za čtení dat z textu požadavku. Chcete-li tento proces přizpůsobit, nakonfigurujte rozhraní API používaná vstupním formátovačem. Tato část popisuje, jak přizpůsobit System.Text.Jsonformátovací modul založený na vstupu, aby porozuměl vlastnímu typu s názvem ObjectId.

Zvažte následující model, který obsahuje vlastní ObjectId vlastnost s názvem Id:

public class ModelWithObjectId
{
    public ObjectId Id { get; set; }
}

Chcete-li přizpůsobit proces vazby modelu při použití System.Text.Json, vytvořte třídu odvozenou z JsonConverter<T>:

internal class ObjectIdConverter : JsonConverter<ObjectId>
{
    public override ObjectId Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return new ObjectId(JsonSerializer.Deserialize<int>(ref reader, options));
    }

    public override void Write(
        Utf8JsonWriter writer, ObjectId value, JsonSerializerOptions options)
    {
        writer.WriteNumberValue(value.Id);
    }
}

Chcete-li použít vlastní převaděč, použijte atribut JsonConverterAttribute na typ. V následujícím příkladu ObjectId je typ nakonfigurován ObjectIdConverter jako vlastní převaděč:

[JsonConverter(typeof(ObjectIdConverter))]
public struct ObjectId
{
    public ObjectId(int id) =>
        Id = id;

    public int Id { get; }
}

Další informace najdete v tématu Jak psát vlastní převaděče.

Vyloučení zadaných typů z vazby modelu

Chování vazeb modelu a ověřovacích systémů je řízeno ModelMetadata. Můžete přizpůsobit ModelMetadata přidáním zprostředkovatele podrobností do MvcOptions.ModelMetadataDetailsProviders. Předdefinované zprostředkovatelé podrobností jsou k dispozici pro zakázání vazby modelu nebo ověření pro zadané typy.

Pokud chcete zakázat vazbu modelu u všech modelů zadaného typu, přidejte do ExcludeBindingMetadataProviderStartup.ConfigureServicessouboru . Pokud chcete například zakázat vazbu modelu u všech modelů typu System.Version:

services.AddRazorPages()
    .AddMvcOptions(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
    options.ModelMetadataDetailsProviders.Add(
        new ExcludeBindingMetadataProvider(typeof(System.Version)));
    options.ModelMetadataDetailsProviders.Add(
        new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters();

Chcete-li zakázat ověřování vlastností zadaného typu, přidejte do SuppressChildValidationMetadataProviderStartup.ConfigureServicessouboru . Pokud chcete například zakázat ověřování u vlastností typu System.Guid:

services.AddRazorPages()
    .AddMvcOptions(options =>
{
    options.ValueProviderFactories.Add(new CookieValueProviderFactory());
    options.ModelMetadataDetailsProviders.Add(
        new ExcludeBindingMetadataProvider(typeof(System.Version)));
    options.ModelMetadataDetailsProviders.Add(
        new SuppressChildValidationMetadataProvider(typeof(System.Guid)));
})
.AddXmlSerializerFormatters();

Vlastní pořadače modelů

Vazby modelu můžete rozšířit tak, že napíšete vlastní vazbu modelu a pomocí atributu [ModelBinder] ji vyberete pro daný cíl. Přečtěte si další informace o vazbě vlastního modelu.

Ruční vazba modelu

Vazbu modelu je možné ručně vyvolat pomocí TryUpdateModelAsync metody. Metoda je definována v obou ControllerBasePageModel třídách. Přetížení metody umožňují zadat předponu a zprostředkovatele hodnot, který se má použít. Metoda vrátí false , pokud dojde k selhání vazby modelu. Tady je příklad:

if (await TryUpdateModelAsync<InstructorWithCollection>(
    newInstructor,
    "Instructor",
    i => i.FirstMidName, i => i.LastName, i => i.HireDate))
{
    _instructorsInMemoryStore.Add(newInstructor);
    return RedirectToPage("./Index");
}
PopulateAssignedCourseData(newInstructor);
return Page();

TryUpdateModelAsync používá zprostředkovatele hodnot k získání dat z textu formuláře, řetězce dotazu a směrování dat. TryUpdateModelAsync obvykle:

  • Používá se s aplikacemi Razor Pages a MVC pomocí kontrolerů a zobrazení, aby se zabránilo nadměrnému publikování.
  • Nepoužívá se s webovým rozhraním API, pokud se nepoužívá z dat formuláře, řetězců dotazů a směruje data. Koncové body webového rozhraní API, které využívají funkci JSON, používají k deserializaci textu požadavku do objektu.

Další informace naleznete v tématu TryUpdateModelAsync.

Atribut [FromServices]

Název tohoto atributu se řídí vzorem atributů vazby modelu, které určují zdroj dat. Nejedná se ale o vazby dat od zprostředkovatele hodnot. Získá instanci typu z kontejneru injektáže závislostí . Jeho účelem je poskytnout alternativu k injektáži konstruktoru, pokud potřebujete službu pouze v případě, že je volána konkrétní metoda.

Další materiály