Poznámka
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální vydání najdete v verzi .NET 9 tohoto článku.
Varování
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální vydání najdete v verzi .NET 9 tohoto článku.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální vydání najdete v verzi .NET 9 tohoto článku.
Tento článek vysvětluje, co je vazba modelu, jak funguje a jak přizpůsobit její 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 mohou poskytnout klíč záznamu a odeslaná pole formuláře mohou poskytovat hodnoty pro vlastnosti modelu. Psaní kódu pro načtení každé z těchto hodnot a převodu z řetězců na typy .NET by bylo zdlouhavé a náchylné k chybám. Modelová vazba tento proces automatizuje. Systém vazeb modelu:
- Načte data z různých zdrojů, jako jsou údaje o trasách, pole formulářů a řetězce dotazů.
- Poskytuje data pro kontrolery a Razor stránky 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:
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
GetById
, celé číslo s názvemid
. - Projde dostupné zdroje v požadavku HTTP a ve směrovacích datech najde
id
= "2". - Převede řetězec "2" na celé číslo 2.
- Najde další parametr
GetById
, což je logická hodnota, nazvanýdogsOnly
. - Projde zdroje a v řetězci dotazu najde "DogsOnly=true". Porovnávání názvů není citlivé na písmena.
- Převede řetězec "true" na logickou hodnotu
true
.
Architektura volá metodu GetById
, předává 2 pro parametr id
a true
pro parametr dogsOnly
.
V předchozím příkladu jsou cílové 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 .
Cíle
Vazba modelu se pokouší najít hodnoty pro následující cílové objekty:
- 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, aby byla vazba modelu zaměřena 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ázány pro požadavky HTTP GET. Obvykle stačí k požadavku GET parametr ID záznamu. ID záznamu slouží k vyhledání položky v databázi. Proto není nutné svázat vlastnost, která obsahuje instanci modelu. Ve scénářích, ve kterých chcete 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; }
Jednoduché a komplexní typy vazby modelu
Modelové přiřazení používá konkrétní definice pro typy, se kterými pracuje. Jednoduchý typ je převeden z jednoho řetězce pomocí metody TypeConverter nebo TryParse
.
Komplexní typ je převeden z více vstupních hodnot. Rámec určuje rozdíl na základě existence TypeConverter
nebo TryParse
. Doporučujeme vytvořit převodník typů nebo použít TryParse
pro převod z string
na SomeType
, který nevyžaduje externí prostředky nebo více vstupů.
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:
- Pole formuláře
- Text požadavku (pro kontrolery, které mají atribut [ApiController].)
- Údaje o trase
- Parametry dotazového řetězce
- 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ěrovací data a řetězcové hodnoty dotazu se používají jenom pro jednoduché typy.
- Nahrané soubory jsou vázány pouze na cílové typy, které implementují
IFormFile
neboIEnumerable<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 polí publikovaného 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ě, a 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ě 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 hlavička s pomlčkou v názvu, jak je znázorněno 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č. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
Při [FromBody]
použití u parametru komplexního 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 těla:
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; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
V předchozím příkladu:
- Atribut
[FromQuery]
je ignorován. - Vlastnost
Breed
není naplněna parametrem řetězce dotazu.
Vstupní formátovací moduly čtou pouze tělo a nerozumí atributům zdroje vazby. Pokud je v těle nalezena vhodná hodnota, tato hodnota se použije k naplnění Breed
atributu.
Nepoužívejte [FromBody]
na více než jeden parametr v rámci jedné akce. Jakmile stream požadavku načte vstupní formátovací modul, nebude už k dispozici ke čtení pro vazbu dalších [FromBody]
parametrů.
Další zdroje
Zdrojová data jsou poskytována systému modelového propojení 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 souborů cookie nebo stavu relace. 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.cs
souboru.
Ukázka obsahuje příklad poskytovatele hodnot a továrny, který získává hodnoty ze souborů cookie. Registrovat vlastní továrny zprostředkovatele hodnot v Program.cs
:
builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});
Předchozí 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:
- Nullable jednoduché typy jsou nastaveny na
null
. - Typy hodnot, které nemohou mít hodnotu null, jsou nastaveny na
default(T)
. Například parametrint id
je nastaven na hodnotu 0. - V případě komplexních typů vytvoří vazba modelu instanci pomocí výchozího konstruktoru bez nastavení vlastností.
- Pole jsou nastavena na
Array.Empty<T>()
, kromě toho, žebyte[]
pole jsou nastavena nanull
.
Pokud by stav modelu měl být neplatný, pokud se v polích formuláře pro vlastnost modelu nenajde nic, použijte [BindRequired]
atribut.
Všimněte si, že toto chování [BindRequired]
platí pro vazbu modelu z publikovaných dat formuláře, ne z dat JSON 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 najde zdroj, ale nejde ho 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, výsledkem neplatného stavu modelu je automatická odpověď HTTP 400.
Na Razor stránce znovu zobrazte chybovou zprávu.
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
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 chcete znovu zobrazit špatná data v poli formuláře, zvažte, jestli je vlastnost modelu řetězec a provést převod dat ručně.
Stejná strategie se doporučuje, pokud nechcete, aby chyby převodu typů způsobily chyby stavu modelu. V takovém případě nastavte vlastnost modelu jako řetězec.
Jednoduché typy
Viz Vazba modelu: jednoduché a složité typy pro vysvětlení jednoduchých a složitých typů.
Mezi jednoduché typy, na které může pořadač modelů převést zdrojové řetězce, patří následující:
- Logická hodnota
- Bajt, SByte
- Znak
- DateOnly
- Datum a čas
- DateTimeOffset
- Desetinné číslo
- Dvojité
- Výčet
- Identifikátor GUID
- Int16, Int32, Int64
- Jednoduchý
- TimeOnly
- Časový rozsah
- UInt16, UInt32, UInt64
- URI
- Verze
Vytvořit vazbu s IParsable<T>.TryParse
Rozhraní IParsable<TSelf>.TryParse
API podporuje vazbu hodnot parametrů akce kontroléru:
public static bool TryParse (string? s, IFormatProvider? provider, out TSelf result);
Následující DateRange
třída implementuje IParsable<TSelf>
k podpoře vazby na rozsah dat:
public class DateRange : IParsable<DateRange>
{
public DateOnly? From { get; init; }
public DateOnly? To { get; init; }
public static DateRange Parse(string value, IFormatProvider? provider)
{
if (!TryParse(value, provider, out var result))
{
throw new ArgumentException("Could not parse supplied value.", nameof(value));
}
return result;
}
public static bool TryParse(string? value,
IFormatProvider? provider, out DateRange dateRange)
{
var segments = value?.Split(',', StringSplitOptions.RemoveEmptyEntries
| StringSplitOptions.TrimEntries);
if (segments?.Length == 2
&& DateOnly.TryParse(segments[0], provider, out var fromDate)
&& DateOnly.TryParse(segments[1], provider, out var toDate))
{
dateRange = new DateRange { From = fromDate, To = toDate };
return true;
}
dateRange = new DateRange { From = default, To = default };
return false;
}
}
Předchozí kód:
- Převede řetězec představující dvě kalendářní data na
DateRange
objekt. - Pořadač modelu používá metodu
IParsable<TSelf>.TryParse
k navázáníDateRange
.
Akce následujícího kontroleru používá třídu DateRange
pro vazbu časového období.
// GET /WeatherForecast/ByRange?range=7/24/2022,07/26/2022
public IActionResult ByRange([FromQuery] DateRange range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= range.From
&& DateOnly.FromDateTime(wf.Date) <= range.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d"),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Následující Locale
třída implementuje podporu vazby IParsable<TSelf>
na CultureInfo
:
public class Locale : CultureInfo, IParsable<Locale>
{
public Locale(string culture) : base(culture)
{
}
public static Locale Parse(string value, IFormatProvider? provider)
{
if (!TryParse(value, provider, out var result))
{
throw new ArgumentException("Could not parse supplied value.", nameof(value));
}
return result;
}
public static bool TryParse([NotNullWhen(true)] string? value,
IFormatProvider? provider, out Locale locale)
{
if (value is null)
{
locale = new Locale(CurrentCulture.Name);
return false;
}
try
{
locale = new Locale(value);
return true;
}
catch (CultureNotFoundException)
{
locale = new Locale(CurrentCulture.Name);
return false;
}
}
}
Následující akce kontroleru používá třídu Locale
pro svázání řetězce CultureInfo
.
// GET /en-GB/WeatherForecast
public IActionResult Index([FromRoute] Locale locale)
{
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d", locale),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View(weatherForecasts);
}
Následující akce kontroleru používá DateRange
a Locale
třídy k vytvoření vazby rozsahu dat s CultureInfo
:
// GET /af-ZA/WeatherForecast/RangeByLocale?range=2022-07-24,2022-07-29
public IActionResult RangeByLocale([FromRoute] Locale locale, [FromQuery] string range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
if (!DateRange.TryParse(range, locale, out DateRange rangeResult))
{
ModelState.TryAddModelError(nameof(range),
$"Invalid date range: {range} for locale {locale.DisplayName}");
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
}
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= rangeResult.From
&& DateOnly.FromDateTime(wf.Date) <= rangeResult.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d", locale),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int) (wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Ukázková aplikace API na GitHubu ukazuje předchozí ukázku kontroleru rozhraní API.
Vytvořit vazbu s TryParse
Rozhraní TryParse
API podporuje vazbu hodnot parametrů akce kontroléru:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
IParsable<T>.TryParse
je doporučeným přístupem pro vazbu parametrů, protože na rozdíl od TryParse
něj nezávisí na reflexi.
Následující DateRangeTP
třída implementuje TryParse
:
public class DateRangeTP
{
public DateOnly? From { get; }
public DateOnly? To { get; }
public DateRangeTP(string from, string to)
{
if (string.IsNullOrEmpty(from))
throw new ArgumentNullException(nameof(from));
if (string.IsNullOrEmpty(to))
throw new ArgumentNullException(nameof(to));
From = DateOnly.Parse(from);
To = DateOnly.Parse(to);
}
public static bool TryParse(string? value, out DateRangeTP? result)
{
var range = value?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (range?.Length != 2)
{
result = default;
return false;
}
result = new DateRangeTP(range[0], range[1]);
return true;
}
}
Akce následujícího kontroleru používá třídu DateRangeTP
pro vazbu časového období.
// GET /WeatherForecast/ByRangeTP?range=7/24/2022,07/26/2022
public IActionResult ByRangeTP([FromQuery] DateRangeTP range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= range.From
&& DateOnly.FromDateTime(wf.Date) <= range.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d"),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Komplexní typy
Komplexní typ musí mít veřejné výchozí konstruktor a veřejné zapisovatelné vlastnosti pro vytvoření vazby. Když dojde k vytvoření vazby modelu, vytvoří se instance třídy pomocí veřejného výchozího konstruktoru.
Pro každou vlastnost komplexního typu vazba modelu hledá ve zdrojích vzor názvůprefix.property_name. Pokud se nic nenajde, hledá jenom property_name bez předpony. Rozhodnutí o použití předpony se nedělá pro jednotlivé vlastnosti. Například dotaz obsahující ?Instructor.Id=100&Name=foo
a přiřazený k metodě OnGet(Instructor instructor)
vede k vytvoření objektu typu Instructor
, který obsahuje:
-
Id
nastaveno na100
. -
Name
nastaveno nanull
. Vazba modelu očekáváInstructor.Name
, protožeInstructor.Id
byla použita v předchozím parametru dotazu.
Pro vazbu na parametr je předpona název parametru. Pro vazbu na PageModel
veřejnou vlastnost je předpona název 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; }
}
Předpona = 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á procházením zdrojů klíče instructorToUpdate.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Prefix = 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á procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Vlastní předpona
Pokud je model, který má být vázán, parametr s názvem instructorToUpdate
a Bind
atribut určuje Instructor
jako předponu:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Vazba modelu začíná procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Atributy pro cíle komplexního typu
Pro řízení vazby modelu komplexních typů je k dispozici několik předdefinovaných atributů:
Varování
Tyto atributy ovlivňují vazbu modelu, když jsou zdrojem hodnot data odeslaná formulářem. Nemají vliv na vstupní formátovací moduly, které zpracovávají odeslaná těla požadavků typu JSON a XML. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
[Bind] – atribut
Lze použít na třídu nebo parametr metody. Určuje, které vlastnosti modelu mají být zahrnuty do vazby modelu.
[Bind]
nemá žádný vliv na vstupní formátovací moduly.
V následujícím příkladu jsou vázány pouze zadané vlastnosti Instructor
modelu, pokud je volána jakákoli obslužná rutina nebo metoda akce:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
V následujícím příkladu jsou při zavolání metody Instructor
vázány pouze zadané vlastnosti modelu OnPost
.
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atribut [Bind]
lze použít k ochraně proti nadměrnému umístění ve scénářích vytváření . Nefunguje dobře ve scénářích úprav, protože vyloučené vlastnosti jsou nastavené na hodnotu null nebo výchozí hodnotu, místo aby zůstaly beze změny. Pro ochranu před nadměrném umístěním se místo atributu [Bind]
doporučuje zobrazit modely. Další informace naleznete v tématu Bezpečnostní poznámka o nadměrném příspěvku.
Atribut [ModelBinder]
ModelBinderAttribute lze použít u typů, vlastností nebo parametrů. Umožňuje zadat typ vazebníka modelu použitého pro navázání konkrétní instance nebo typu. Příklad:
[HttpPost]
public IActionResult OnPost(
[ModelBinder<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]
Způsobí, že vazba modelu přidá chybu stavu modelu, pokud vazba nemůže nastat 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. Zabraňuje vazbě modelu v nastavení vlastnosti modelu. Při použití na typ systém vazeb modelu vyloučí 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ů, vazba modelu hledá 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 vytvoření vazby parametru nebo vlastnosti s názvem
index
neboIndex
pokud sousedí s hodnotou kolekce. Vazba modelu se pokusí použítindex
jako index pro kolekci, což může způsobit nesprávnou vazbu. Představte si například následující akci:public IActionResult Post(string index, List<Product> products)
V předchozím kódu se parametr řetězce dotazu
index
sváže s parametremindex
metody a rovněž se použije k vazbě kolekce produktů. Přejmenování parametru nebo použití atributuindex
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í příkladové formáty předává modelová vazba 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 číslony 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 indexy 0 a 2 místo 0 a 1, druhá položka se ignoruje.
Slovníky
V případě Dictionary
cílů vazba modelu hledá 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
Dictionary<int, string>
nazvánselectedCourses
:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Data publikovaného formuláře nebo řetězce dotazu můžou 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 ukázkové formáty uvedené výše předá vazba modelu slovník obsahující dvě položky parametru
selectedCourses
:- selectedCourses["1050"]="Chemie"
- selectedCourses["2000"]="Ekonomie"
Vazby konstruktoru a typy záznamů
Vazba modelu vyžaduje, aby složité typy měly konstruktor bez parametrů.
System.Text.Json
i Newtonsoft.Json
vstupní formátory podporují deserializaci tříd, které nemají bezparametrický konstruktor.
Typy záznamů představují skvělý způsob, jak stručně znázorňovat data v síti. ASP.NET Core podporuje vazbu 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
<label>Name: <input asp-for="Name" /></label>
<br />
<label>Age: <input asp-for="Age" /></label>
Při ověřování typů záznamů modul runtime vyhledává metadata vazby a ověřování, a to konkrétně u parametrů, nikoli u vlastností.
Architektura umožňuje vazbu na typy 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:
- Být typem záznamu.
- Má 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 velikostí písmen.
POCOs bez konstruktorů bez parametrů
POCOs, které nemají bezparametrové konstruktory, nelze napojit.
Výsledkem následujícího kódu je výjimka, která říká, že typ musí mít konstruktor bez parametrů:
public class Person {
public 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ě napsanými konstruktory
Typy záznamů s ručně vytvořenými konstruktory, které se podobají primárním konstruktorům, fungují
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 pro vazby
U typů 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 oba 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 vytvoření vazby Name
znovu.
Age
Je však možné je aktualizovat.
Chování globalizace vázání modelu, data směrování a řetězce dotazů.
Poskytovatel hodnot trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu:
- Zacházejte s hodnotami jako s invariantní kulturou.
- Počítejte s tím, že adresy URL jsou nezávislé na kultuře.
Naproti tomu hodnoty pocházející z dat formuláře podléhají kulturně citlivému převodu. Je to záměrně tak, aby adresy URL byly sdíleny napříč národními prostředími.
Aby poskytovatel hodnoty trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu prošly převodem citlivým na kulturní specifika:
- Dědit z IValueProviderFactory
- Zkopírování kódu z QueryStringValueProviderFactory nebo RouteValueValueProviderFactory
- Nahraďte hodnotu jazykové verze předanou konstruktoru zprostředkovatele hodnot CultureInfo.CurrentCulture.
- Nahraďte výchozí objekt pro vytváření zprostředkovatelů hodnot v možnostech MVC novým objektem:
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
Existuje několik speciálních datových typů, které lze zpracovat vazbou modelu.
IFormFile a IFormFileCollection
Nahraný soubor zahrnutý v požadavku HTTP. Také je podporováno IEnumerable<IFormFile>
pro více souborů.
token pro zrušení
Akce můžou volitelně svázat CancellationToken
jako parametr. Tím se prováže RequestAborted, který signalizuje, kdy je přerušeno připojení, které je základem požadavku HTTP. Akce můžou tento parametr použít ke zrušení dlouhotrvajících asynchronních operací, které se spouští jako součást akcí kontroleru.
Kolekce formulářů
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 ve formátu JSON, XML nebo jiném formátu. K analýze těchto dat používá vazba modelu vstupní formátovací modul , který je nakonfigurovaný pro zpracování konkrétního typu obsahu. Ve výchozím nastavení ASP.NET Core obsahuje vstupní formátovací moduly založené na FORMÁTU JSON pro zpracování dat JSON. 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.
Pro použití zabudovaných XML formátovačů:
V
Program.cs
volejte AddXmlSerializerFormatters nebo AddXmlDataContractSerializerFormatters.builder.Services.AddControllers() .AddXmlSerializerFormatters();
Consumes
Použijte atribut na třídy kontroleru nebo metody akcí, které by měly očekávat KÓD 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. Pokud chcete tento proces přizpůsobit, nakonfigurujte rozhraní API používaná vstupním formátovacím modulem. Tato část popisuje, jak přizpůsobit vstupní formátovací modul založený na System.Text.Json
pro pochopení vlastního typu s názvem ObjectId
.
Představte si následující model, který obsahuje vlastní ObjectId
vlastnost:
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 JsonConverterAttribute atribut na typ. V následujícím příkladu je typ ObjectId
nakonfigurován jako vlastní převaděč s ObjectIdConverter
.
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
Další informace naleznete 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. Ke ModelMetadata
můžete přidat zprostředkovatele podrobností, abyste provedli úpravy . Zprostředkovatelé předdefinovaných podrobností jsou k dispozici pro zakázání vazby nebo ověřování modelu pro zadané typy.
Chcete-li zakázat vazbu modelu u všech modelů určitého typu, přidejte do ExcludeBindingMetadataProviderProgram.cs
. Chcete-li 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í u vlastností zadaného typu, přidejte SuppressChildValidationMetadataProvider do Program.cs
souboru . Chcete-li 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í pořadač modelů a pomocí atributu [ModelBinder]
ho vyberete pro daný cíl. Přečtěte si další informace o vazbě vlastního modelu.
Ruční vazba modelu
Vazbu modelu lze vyvolat ručně pomocí TryUpdateModelAsync metody. Metoda je definována na obou třídách ControllerBase
a PageModel
. Přetížení metod vám umožní zadat předponu a zprostředkovatele hodnot, které chcete použít. Metoda vrátí false
, pokud se nezdaří vazba modelu. 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
je 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í používán s daty z formulářů, řetězci dotazů, a daty trasy. Koncové body webového rozhraní API, které využívají JSON, používají k deserializaci textu požadavku do objektu vstupní formátovací moduly.
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 z poskytovatele hodnot. Získá instanci typu z kontejneru injektáže závislostí. Jejím účelem je poskytnout alternativu k injekci pomocí konstruktoru, pro případy, kdy potřebujete službu pouze, pokud je zavolá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ů:
- Zajistit, aby byl parametr volitelný s hodnotou 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.
Další materiály
Tento článek vysvětluje, co je vazba modelu, jak funguje a jak přizpůsobit její 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 mohou poskytnout klíč záznamu a odeslaná pole formuláře mohou poskytovat hodnoty pro vlastnosti modelu. Psaní kódu pro načtení každé z těchto hodnot a převodu z řetězců na typy .NET by bylo zdlouhavé a náchylné k chybám. Modelová vazba tento proces automatizuje. Systém vazeb modelu:
- Načte data z různých zdrojů, jako jsou údaje o trasách, pole formulářů a řetězce dotazů.
- Poskytuje data pro kontrolery a Razor stránky 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:
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
GetById
, celé číslo s názvemid
. - Projde dostupné zdroje v požadavku HTTP a ve směrovacích datech najde
id
= "2". - Převede řetězec "2" na celé číslo 2.
- Najde další parametr
GetById
, což je logická hodnota, nazvanýdogsOnly
. - Projde zdroje a v řetězci dotazu najde "DogsOnly=true". Porovnávání názvů není citlivé na písmena.
- Převede řetězec "true" na logickou hodnotu
true
.
Architektura volá metodu GetById
, předává 2 pro parametr id
a true
pro parametr dogsOnly
.
V předchozím příkladu jsou cílové 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 .
Cíle
Vazba modelu se pokouší najít hodnoty pro následující cílové objekty:
- 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, aby byla vazba modelu zaměřena 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ázány pro požadavky HTTP GET. Obvykle stačí k požadavku GET parametr ID záznamu. ID záznamu slouží k vyhledání položky v databázi. Proto není nutné svázat vlastnost, která obsahuje instanci modelu. Ve scénářích, ve kterých chcete 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; }
Jednoduché a komplexní typy vazby modelu
Modelové přiřazení používá konkrétní definice pro typy, se kterými pracuje. Jednoduchý typ je převeden z jednoho řetězce pomocí metody TypeConverter nebo TryParse
.
Komplexní typ je převeden z více vstupních hodnot. Rámec určuje rozdíl na základě existence TypeConverter
nebo TryParse
. Doporučujeme vytvořit převodník typů nebo použít TryParse
pro převod z string
na SomeType
, který nevyžaduje externí prostředky nebo více vstupů.
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:
- Pole formuláře
- Text požadavku (pro kontrolery, které mají atribut [ApiController].)
- Údaje o trase
- Parametry dotazového řetězce
- 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ěrovací data a řetězcové hodnoty dotazu se používají jenom pro jednoduché typy.
- Nahrané soubory jsou vázány pouze na cílové typy, které implementují
IFormFile
neboIEnumerable<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 polí publikovaného 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ě, a 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ě 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 hlavička s pomlčkou v názvu, jak je znázorněno 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č. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
Při [FromBody]
použití u parametru komplexního 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 těla:
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; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
V předchozím příkladu:
- Atribut
[FromQuery]
je ignorován. - Vlastnost
Breed
není naplněna parametrem řetězce dotazu.
Vstupní formátovací moduly čtou pouze tělo a nerozumí atributům zdroje vazby. Pokud je v těle nalezena vhodná hodnota, tato hodnota se použije k naplnění Breed
atributu.
Nepoužívejte [FromBody]
na více než jeden parametr v rámci jedné akce. Jakmile stream požadavku načte vstupní formátovací modul, nebude už k dispozici ke čtení pro vazbu dalších [FromBody]
parametrů.
Další zdroje
Zdrojová data jsou poskytována systému modelového propojení 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 souborů cookie nebo stavu relace. 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.cs
souboru.
Ukázka obsahuje příklad poskytovatele hodnot a továrny, který získává hodnoty ze souborů cookie. Registrovat vlastní továrny zprostředkovatele hodnot v Program.cs
:
builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});
Předchozí 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:
- Nullable jednoduché typy jsou nastaveny na
null
. - Typy hodnot, které nemohou mít hodnotu null, jsou nastaveny na
default(T)
. Například parametrint id
je nastaven na hodnotu 0. - V případě komplexních typů vytvoří vazba modelu instanci pomocí výchozího konstruktoru bez nastavení vlastností.
- Pole jsou nastavena na
Array.Empty<T>()
, kromě toho, žebyte[]
pole jsou nastavena nanull
.
Pokud by stav modelu měl být 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í platí pro vazbu modelu z publikovaných dat formuláře, ne pro data JSON 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 najde zdroj, ale nejde ho 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, výsledkem neplatného stavu modelu je automatická odpověď HTTP 400.
Na Razor stránce znovu zobrazte chybovou zprávu.
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
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 chcete znovu zobrazit špatná data v poli formuláře, zvažte, jestli je vlastnost modelu řetězec a provést převod dat ručně.
Stejná strategie se doporučuje, pokud nechcete, aby chyby převodu typů způsobily chyby stavu modelu. V takovém případě nastavte vlastnost modelu jako řetězec.
Jednoduché typy
Viz Vazba modelu: jednoduché a složité typy pro vysvětlení jednoduchých a složitých typů.
Mezi jednoduché typy, na které může pořadač modelů převést zdrojové řetězce, patří následující:
- Logická hodnota
- Bajt, SByte
- Znak
- DateOnly
- Datum a čas
- DateTimeOffset
- Desetinné číslo
- Dvojité
- Výčet
- Identifikátor GUID
- Int16, Int32, Int64
- Jednoduchý
- TimeOnly
- Časový rozsah
- UInt16, UInt32, UInt64
- URI
- Verze
Vytvořit vazbu s IParsable<T>.TryParse
Rozhraní IParsable<TSelf>.TryParse
API podporuje vazbu hodnot parametrů akce kontroléru:
public static bool TryParse (string? s, IFormatProvider? provider, out TSelf result);
Následující DateRange
třída implementuje IParsable<TSelf>
k podpoře vazby na rozsah dat:
public class DateRange : IParsable<DateRange>
{
public DateOnly? From { get; init; }
public DateOnly? To { get; init; }
public static DateRange Parse(string value, IFormatProvider? provider)
{
if (!TryParse(value, provider, out var result))
{
throw new ArgumentException("Could not parse supplied value.", nameof(value));
}
return result;
}
public static bool TryParse(string? value,
IFormatProvider? provider, out DateRange dateRange)
{
var segments = value?.Split(',', StringSplitOptions.RemoveEmptyEntries
| StringSplitOptions.TrimEntries);
if (segments?.Length == 2
&& DateOnly.TryParse(segments[0], provider, out var fromDate)
&& DateOnly.TryParse(segments[1], provider, out var toDate))
{
dateRange = new DateRange { From = fromDate, To = toDate };
return true;
}
dateRange = new DateRange { From = default, To = default };
return false;
}
}
Předchozí kód:
- Převede řetězec představující dvě kalendářní data na
DateRange
objekt. - Pořadač modelu používá metodu
IParsable<TSelf>.TryParse
k navázáníDateRange
.
Akce následujícího kontroleru používá třídu DateRange
pro vazbu časového období.
// GET /WeatherForecast/ByRange?range=7/24/2022,07/26/2022
public IActionResult ByRange([FromQuery] DateRange range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= range.From
&& DateOnly.FromDateTime(wf.Date) <= range.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d"),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Následující Locale
třída implementuje podporu vazby IParsable<TSelf>
na CultureInfo
:
public class Locale : CultureInfo, IParsable<Locale>
{
public Locale(string culture) : base(culture)
{
}
public static Locale Parse(string value, IFormatProvider? provider)
{
if (!TryParse(value, provider, out var result))
{
throw new ArgumentException("Could not parse supplied value.", nameof(value));
}
return result;
}
public static bool TryParse([NotNullWhen(true)] string? value,
IFormatProvider? provider, out Locale locale)
{
if (value is null)
{
locale = new Locale(CurrentCulture.Name);
return false;
}
try
{
locale = new Locale(value);
return true;
}
catch (CultureNotFoundException)
{
locale = new Locale(CurrentCulture.Name);
return false;
}
}
}
Následující akce kontroleru používá třídu Locale
pro svázání řetězce CultureInfo
.
// GET /en-GB/WeatherForecast
public IActionResult Index([FromRoute] Locale locale)
{
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d", locale),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View(weatherForecasts);
}
Následující akce kontroleru používá DateRange
a Locale
třídy k vytvoření vazby rozsahu dat s CultureInfo
:
// GET /af-ZA/WeatherForecast/RangeByLocale?range=2022-07-24,2022-07-29
public IActionResult RangeByLocale([FromRoute] Locale locale, [FromQuery] string range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
if (!DateRange.TryParse(range, locale, out DateRange rangeResult))
{
ModelState.TryAddModelError(nameof(range),
$"Invalid date range: {range} for locale {locale.DisplayName}");
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
}
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= rangeResult.From
&& DateOnly.FromDateTime(wf.Date) <= rangeResult.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d", locale),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int) (wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Ukázková aplikace API na GitHubu ukazuje předchozí ukázku kontroleru rozhraní API.
Vytvořit vazbu s TryParse
Rozhraní TryParse
API podporuje vazbu hodnot parametrů akce kontroléru:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
IParsable<T>.TryParse
je doporučeným přístupem pro vazbu parametrů, protože na rozdíl od TryParse
něj nezávisí na reflexi.
Následující DateRangeTP
třída implementuje TryParse
:
public class DateRangeTP
{
public DateOnly? From { get; }
public DateOnly? To { get; }
public DateRangeTP(string from, string to)
{
if (string.IsNullOrEmpty(from))
throw new ArgumentNullException(nameof(from));
if (string.IsNullOrEmpty(to))
throw new ArgumentNullException(nameof(to));
From = DateOnly.Parse(from);
To = DateOnly.Parse(to);
}
public static bool TryParse(string? value, out DateRangeTP? result)
{
var range = value?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (range?.Length != 2)
{
result = default;
return false;
}
result = new DateRangeTP(range[0], range[1]);
return true;
}
}
Akce následujícího kontroleru používá třídu DateRangeTP
pro vazbu časového období.
// GET /WeatherForecast/ByRangeTP?range=7/24/2022,07/26/2022
public IActionResult ByRangeTP([FromQuery] DateRangeTP range)
{
if (!ModelState.IsValid)
return View("Error", ModelState.Values.SelectMany(v => v.Errors));
var weatherForecasts = Enumerable
.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.Where(wf => DateOnly.FromDateTime(wf.Date) >= range.From
&& DateOnly.FromDateTime(wf.Date) <= range.To)
.Select(wf => new WeatherForecastViewModel
{
Date = wf.Date.ToString("d"),
TemperatureC = wf.TemperatureC,
TemperatureF = 32 + (int)(wf.TemperatureC / 0.5556),
Summary = wf.Summary
});
return View("Index", weatherForecasts);
}
Komplexní typy
Komplexní typ musí mít veřejné výchozí konstruktor a veřejné zapisovatelné vlastnosti pro vytvoření vazby. Když dojde k vytvoření vazby modelu, vytvoří se instance třídy pomocí veřejného výchozího konstruktoru.
Pro každou vlastnost komplexního typu vazba modelu hledá ve zdrojích vzor názvůprefix.property_name. Pokud se nic nenajde, hledá jenom property_name bez předpony. Rozhodnutí o použití předpony se nedělá pro jednotlivé vlastnosti. Například dotaz obsahující ?Instructor.Id=100&Name=foo
a přiřazený k metodě OnGet(Instructor instructor)
vede k vytvoření objektu typu Instructor
, který obsahuje:
-
Id
nastaveno na100
. -
Name
nastaveno nanull
. Vazba modelu očekáváInstructor.Name
, protožeInstructor.Id
byla použita v předchozím parametru dotazu.
Pro vazbu na parametr je předpona název parametru. Pro vazbu na PageModel
veřejnou vlastnost je předpona název 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; }
}
Předpona = 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á procházením zdrojů klíče instructorToUpdate.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Prefix = 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á procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Vlastní předpona
Pokud je model, který má být vázán, parametr s názvem instructorToUpdate
a Bind
atribut určuje Instructor
jako předponu:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Vazba modelu začíná procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Atributy pro cíle komplexního typu
Pro řízení vazby modelu komplexních typů je k dispozici několik předdefinovaných atributů:
Varování
Tyto atributy ovlivňují vazbu modelu, když jsou zdrojem hodnot data odeslaná formulářem. Nemají vliv na vstupní formátovací moduly, které zpracovávají odeslaná těla požadavků typu JSON a XML. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
[Bind] – atribut
Lze použít na třídu nebo parametr metody. Určuje, které vlastnosti modelu mají být zahrnuty do vazby modelu.
[Bind]
nemá žádný vliv na vstupní formátovací moduly.
V následujícím příkladu jsou vázány pouze zadané vlastnosti Instructor
modelu, pokud je volána jakákoli obslužná rutina nebo metoda akce:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
V následujícím příkladu jsou při zavolání metody Instructor
vázány pouze zadané vlastnosti modelu OnPost
.
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atribut [Bind]
lze použít k ochraně proti nadměrnému umístění ve scénářích vytváření . Nefunguje dobře ve scénářích úprav, protože vyloučené vlastnosti jsou nastavené na hodnotu null nebo výchozí hodnotu, místo aby zůstaly beze změny. Pro ochranu před nadměrném umístěním se místo atributu [Bind]
doporučuje zobrazit modely. Další informace naleznete v tématu Bezpečnostní poznámka o nadměrném příspěvku.
Atribut [ModelBinder]
ModelBinderAttribute lze použít u typů, vlastností nebo parametrů. Umožňuje zadat typ vazebníka modelu použitého pro navázání 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]
Způsobí, že vazba modelu přidá chybu stavu modelu, pokud vazba nemůže nastat 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. Zabraňuje vazbě modelu v nastavení vlastnosti modelu. Při použití na typ systém vazeb modelu vyloučí 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ů, vazba modelu hledá 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 vytvoření vazby parametru nebo vlastnosti s názvem
index
neboIndex
pokud sousedí s hodnotou kolekce. Vazba modelu se pokusí použítindex
jako index pro kolekci, což může způsobit nesprávnou vazbu. Představte si například následující akci:public IActionResult Post(string index, List<Product> products)
V předchozím kódu se parametr řetězce dotazu
index
sváže s parametremindex
metody a rovněž se použije k vazbě kolekce produktů. Přejmenování parametru nebo použití atributuindex
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í příkladové formáty předává modelová vazba 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 číslony 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 indexy 0 a 2 místo 0 a 1, druhá položka se ignoruje.
Slovníky
V případě Dictionary
cílů vazba modelu hledá 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
Dictionary<int, string>
nazvánselectedCourses
:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Data publikovaného formuláře nebo řetězce dotazu můžou 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 ukázkové formáty uvedené výše předá vazba modelu slovník obsahující dvě položky parametru
selectedCourses
:- selectedCourses["1050"]="Chemie"
- selectedCourses["2000"]="Ekonomie"
Vazby konstruktoru a typy záznamů
Vazba modelu vyžaduje, aby složité typy měly konstruktor bez parametrů.
System.Text.Json
i Newtonsoft.Json
vstupní formátory podporují deserializaci tříd, které nemají bezparametrický konstruktor.
Typy záznamů představují skvělý způsob, jak stručně znázorňovat data v síti. ASP.NET Core podporuje vazbu 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
<label>Name: <input asp-for="Name" /></label>
<br />
<label>Age: <input asp-for="Age" /></label>
Při ověřování typů záznamů modul runtime vyhledává metadata vazby a ověřování, a to konkrétně u parametrů, nikoli u vlastností.
Architektura umožňuje vazbu na typy 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:
- Být typem záznamu.
- Má 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 velikostí písmen.
POCOs bez konstruktorů bez parametrů
POCOs, které nemají bezparametrové konstruktory, nelze napojit.
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ě napsanými konstruktory
Typy záznamů s ručně vytvořenými konstruktory, které se podobají primárním konstruktorům, fungují
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 pro vazby
U typů 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 oba 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 vytvoření vazby Name
znovu.
Age
Je však možné je aktualizovat.
Chování globalizace vázání modelu, data směrování a řetězce dotazů.
Poskytovatel hodnot trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu:
- Zacházejte s hodnotami jako s invariantní kulturou.
- Počítejte s tím, že adresy URL jsou nezávislé na kultuře.
Naproti tomu hodnoty pocházející z dat formuláře podléhají kulturně citlivému převodu. Je to záměrně tak, aby adresy URL byly sdíleny napříč národními prostředími.
Aby poskytovatel hodnoty trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu prošly převodem citlivým na kulturní specifika:
- Dědit z IValueProviderFactory
- Zkopírování kódu z QueryStringValueProviderFactory nebo RouteValueValueProviderFactory
- Nahraďte hodnotu jazykové verze předanou konstruktoru zprostředkovatele hodnot CultureInfo.CurrentCulture.
- Nahraďte výchozí objekt pro vytváření zprostředkovatelů hodnot v možnostech MVC novým objektem:
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
Existuje několik speciálních datových typů, které lze zpracovat vazbou modelu.
IFormFile a IFormFileCollection
Nahraný soubor zahrnutý v požadavku HTTP. Také je podporováno IEnumerable<IFormFile>
pro více souborů.
token pro zrušení
Akce můžou volitelně svázat CancellationToken
jako parametr. Tím se prováže RequestAborted, který signalizuje, kdy je přerušeno připojení, které je základem požadavku HTTP. Akce můžou tento parametr použít ke zrušení dlouhotrvajících asynchronních operací, které se spouští jako součást akcí kontroleru.
Kolekce formulářů
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 ve formátu JSON, XML nebo jiném formátu. K analýze těchto dat používá vazba modelu vstupní formátovací modul , který je nakonfigurovaný pro zpracování konkrétního typu obsahu. Ve výchozím nastavení ASP.NET Core obsahuje vstupní formátovací moduly založené na FORMÁTU JSON pro zpracování dat JSON. 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.
Pro použití zabudovaných XML formátovačů:
V
Program.cs
volejte AddXmlSerializerFormatters nebo AddXmlDataContractSerializerFormatters.builder.Services.AddControllers() .AddXmlSerializerFormatters();
Consumes
Použijte atribut na třídy kontroleru nebo metody akcí, které by měly očekávat KÓD 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. Pokud chcete tento proces přizpůsobit, nakonfigurujte rozhraní API používaná vstupním formátovacím modulem. Tato část popisuje, jak přizpůsobit vstupní formátovací modul založený na System.Text.Json
pro pochopení vlastního typu s názvem ObjectId
.
Představte si následující model, který obsahuje vlastní ObjectId
vlastnost:
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 JsonConverterAttribute atribut na typ. V následujícím příkladu je typ ObjectId
nakonfigurován jako vlastní převaděč s ObjectIdConverter
.
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
Další informace naleznete 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. Ke ModelMetadata
můžete přidat zprostředkovatele podrobností, abyste provedli úpravy . Zprostředkovatelé předdefinovaných podrobností jsou k dispozici pro zakázání vazby nebo ověřování modelu pro zadané typy.
Chcete-li zakázat vazbu modelu u všech modelů určitého typu, přidejte do ExcludeBindingMetadataProviderProgram.cs
. Chcete-li 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í u vlastností zadaného typu, přidejte SuppressChildValidationMetadataProvider do Program.cs
souboru . Chcete-li 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í pořadač modelů a pomocí atributu [ModelBinder]
ho vyberete pro daný cíl. Přečtěte si další informace o vazbě vlastního modelu.
Ruční vazba modelu
Vazbu modelu lze vyvolat ručně pomocí TryUpdateModelAsync metody. Metoda je definována na obou třídách ControllerBase
a PageModel
. Přetížení metod vám umožní zadat předponu a zprostředkovatele hodnot, které chcete použít. Metoda vrátí false
, pokud se nezdaří vazba modelu. 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
je 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í používán s daty z formulářů, řetězci dotazů, a daty trasy. Koncové body webového rozhraní API, které využívají JSON, používají k deserializaci textu požadavku do objektu vstupní formátovací moduly.
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 z poskytovatele hodnot. Získá instanci typu z kontejneru injektáže závislostí. Jejím účelem je poskytnout alternativu k injekci pomocí konstruktoru, pro případy, kdy potřebujete službu pouze, pokud je zavolá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ů:
- Zajistit, aby byl parametr volitelný s hodnotou 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.
Další materiály
Tento článek vysvětluje, co je vazba modelu, jak funguje a jak přizpůsobit její 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 mohou poskytnout klíč záznamu a odeslaná pole formuláře mohou poskytovat hodnoty pro vlastnosti modelu. Psaní kódu pro načtení každé z těchto hodnot a převodu z řetězců na typy .NET by bylo zdlouhavé a náchylné k chybám. Modelová vazba tento proces automatizuje. Systém vazeb modelu:
- Načte data z různých zdrojů, jako jsou údaje o trasách, pole formulářů a řetězce dotazů.
- Poskytuje data pro kontrolery a Razor stránky 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:
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
GetById
, celé číslo s názvemid
. - Projde dostupné zdroje v požadavku HTTP a ve směrovacích datech najde
id
= "2". - Převede řetězec "2" na celé číslo 2.
- Najde další parametr
GetById
, což je logická hodnota, nazvanýdogsOnly
. - Projde zdroje a v řetězci dotazu najde "DogsOnly=true". Porovnávání názvů není citlivé na písmena.
- Převede řetězec "true" na logickou hodnotu
true
.
Architektura volá metodu GetById
, předává 2 pro parametr id
a true
pro parametr dogsOnly
.
V předchozím příkladu jsou cílové 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 .
Cíle
Vazba modelu se pokouší najít hodnoty pro následující cílové objekty:
- 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, aby byla vazba modelu zaměřena 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ázány pro požadavky HTTP GET. Obvykle stačí k požadavku GET parametr ID záznamu. ID záznamu slouží k vyhledání položky v databázi. Proto není nutné svázat vlastnost, která obsahuje instanci modelu. Ve scénářích, ve kterých chcete 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:
- Pole formuláře
- Text požadavku (pro kontrolery, které mají atribut [ApiController].)
- Údaje o trase
- Parametry dotazového řetězce
- 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ěrovací data a řetězcové hodnoty dotazu se používají jenom pro jednoduché typy.
- Nahrané soubory jsou vázány pouze na cílové typy, které implementují
IFormFile
neboIEnumerable<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 polí publikovaného 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ě, a 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ě 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 hlavička s pomlčkou v názvu, jak je znázorněno 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č. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
Při [FromBody]
použití u parametru komplexního 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 těla:
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; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
V předchozím příkladu:
- Atribut
[FromQuery]
je ignorován. - Vlastnost
Breed
není naplněna parametrem řetězce dotazu.
Vstupní formátovací moduly čtou pouze tělo a nerozumí atributům zdroje vazby. Pokud je v těle nalezena vhodná hodnota, tato hodnota se použije k naplnění Breed
atributu.
Nepoužívejte [FromBody]
na více než jeden parametr v rámci jedné akce. Jakmile stream požadavku načte vstupní formátovací modul, nebude už k dispozici ke čtení pro vazbu dalších [FromBody]
parametrů.
Další zdroje
Zdrojová data jsou poskytována systému modelového propojení 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 souborů cookie nebo stavu relace. 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.cs
souboru.
Ukázka obsahuje příklad poskytovatele hodnot a továrny, který získává hodnoty ze souborů cookie. Registrovat vlastní továrny zprostředkovatele hodnot v Program.cs
:
builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});
Předchozí 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, které mohou být null, jsou nastaveny na
null
. - Typy hodnot, které nemohou mít hodnotu null, jsou nastaveny na
default(T)
. Například parametrint id
je nastaven na hodnotu 0. - V případě komplexních typů vytvoří vazba modelu instanci pomocí výchozího konstruktoru bez nastavení vlastností.
- Pole jsou nastavena na
Array.Empty<T>()
, kromě toho, žebyte[]
pole jsou nastavena nanull
.
Pokud by stav modelu měl být 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í platí pro vazbu modelu z publikovaných dat formuláře, ne pro data JSON 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 najde zdroj, ale nejde ho 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, výsledkem neplatného stavu modelu je automatická odpověď HTTP 400.
Na Razor stránce znovu zobrazte chybovou zprávu.
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
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 chcete znovu zobrazit špatná data v poli formuláře, zvažte, jestli je vlastnost modelu řetězec a provést převod dat ručně.
Stejná strategie se doporučuje, pokud nechcete, aby chyby převodu typů způsobily chyby stavu modelu. V takovém případě nastavte vlastnost modelu jako řetězec.
Jednoduché typy
Mezi jednoduché typy, na které může pořadač modelů převést zdrojové řetězce, patří následující:
- Logická hodnota
- Bajt, SByte
- Znak
- Datum a čas
- DateTimeOffset
- Desetinné číslo
- Dvojité
- Výčet
- Identifikátor GUID
- Int16, Int32, Int64
- Jednoduchý
- Časový rozsah
- UInt16, UInt32, UInt64
- URI
- Verze
Komplexní typy
Komplexní typ musí mít veřejné výchozí konstruktor a veřejné zapisovatelné vlastnosti pro vytvoření vazby. Když dojde k vytvoření vazby modelu, vytvoří se instance třídy pomocí veřejného výchozího konstruktoru.
Pro každou vlastnost komplexního typu vazba modelu hledá ve zdrojích vzor názvůprefix.property_name. Pokud se nic nenajde, hledá jenom property_name bez předpony. Rozhodnutí o použití předpony se nedělá pro jednotlivé vlastnosti. Například dotaz obsahující ?Instructor.Id=100&Name=foo
a přiřazený k metodě OnGet(Instructor instructor)
vede k vytvoření objektu typu Instructor
, který obsahuje:
-
Id
nastaveno na100
. -
Name
nastaveno nanull
. Vazba modelu očekáváInstructor.Name
, protožeInstructor.Id
byla použita v předchozím parametru dotazu.
Pro vazbu na parametr je předpona název parametru. Pro vazbu na PageModel
veřejnou vlastnost je předpona název 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; }
}
Předpona = 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á procházením zdrojů klíče instructorToUpdate.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Prefix = 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á procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Vlastní předpona
Pokud je model, který má být vázán, parametr s názvem instructorToUpdate
a Bind
atribut určuje Instructor
jako předponu:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Vazba modelu začíná procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Atributy pro cíle komplexního typu
Pro řízení vazby modelu komplexních typů je k dispozici několik předdefinovaných atributů:
Varování
Tyto atributy ovlivňují vazbu modelu, když jsou zdrojem hodnot data odeslaná formulářem. Nemají vliv na vstupní formátovací moduly, které zpracovávají odeslaná těla požadavků typu JSON a XML. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
[Bind] – atribut
Lze použít na třídu nebo parametr metody. Určuje, které vlastnosti modelu mají být zahrnuty do vazby modelu.
[Bind]
nemá žádný vliv na vstupní formátovací moduly.
V následujícím příkladu jsou vázány pouze zadané vlastnosti Instructor
modelu, pokud je volána jakákoli obslužná rutina nebo metoda akce:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
V následujícím příkladu jsou při zavolání metody Instructor
vázány pouze zadané vlastnosti modelu OnPost
.
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atribut [Bind]
lze použít k ochraně proti nadměrnému umístění ve scénářích vytváření . Nefunguje dobře ve scénářích úprav, protože vyloučené vlastnosti jsou nastavené na hodnotu null nebo výchozí hodnotu, místo aby zůstaly beze změny. Pro ochranu před nadměrném umístěním se místo atributu [Bind]
doporučuje zobrazit modely. Další informace naleznete v tématu Bezpečnostní poznámka o nadměrném příspěvku.
Atribut [ModelBinder]
ModelBinderAttribute lze použít u typů, vlastností nebo parametrů. Umožňuje zadat typ vazebníka modelu použitého pro navázání 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]
Způsobí, že vazba modelu přidá chybu stavu modelu, pokud vazba nemůže nastat 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. Zabraňuje vazbě modelu v nastavení vlastnosti modelu. Při použití na typ systém vazeb modelu vyloučí 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ů, vazba modelu hledá 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 vytvoření vazby parametru nebo vlastnosti s názvem
index
neboIndex
pokud sousedí s hodnotou kolekce. Vazba modelu se pokusí použítindex
jako index pro kolekci, což může způsobit nesprávnou vazbu. Představte si například následující akci:public IActionResult Post(string index, List<Product> products)
V předchozím kódu se parametr řetězce dotazu
index
sváže s parametremindex
metody a rovněž se použije k vazbě kolekce produktů. Přejmenování parametru nebo použití atributuindex
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í příkladové formáty předává modelová vazba 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 číslony 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 indexy 0 a 2 místo 0 a 1, druhá položka se ignoruje.
Slovníky
V případě Dictionary
cílů vazba modelu hledá 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
Dictionary<int, string>
nazvánselectedCourses
:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Data publikovaného formuláře nebo řetězce dotazu můžou 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 ukázkové formáty uvedené výše předá vazba modelu slovník obsahující dvě položky parametru
selectedCourses
:- selectedCourses["1050"]="Chemie"
- selectedCourses["2000"]="Ekonomie"
Vazby konstruktoru a typy záznamů
Vazba modelu vyžaduje, aby složité typy měly konstruktor bez parametrů.
System.Text.Json
i Newtonsoft.Json
vstupní formátory podporují deserializaci tříd, které nemají bezparametrický konstruktor.
Typy záznamů představují skvělý způsob, jak stručně znázorňovat data v síti. ASP.NET Core podporuje vazbu 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
<label>Name: <input asp-for="Name" /></label>
<br />
<label>Age: <input asp-for="Age" /></label>
Při ověřování typů záznamů modul runtime vyhledává metadata vazby a ověřování, a to konkrétně u parametrů, nikoli u vlastností.
Architektura umožňuje vazbu na typy 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:
- Být typem záznamu.
- Má 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 velikostí písmen.
POCOs bez konstruktorů bez parametrů
POCOs, které nemají bezparametrové konstruktory, nelze napojit.
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ě napsanými konstruktory
Typy záznamů s ručně vytvořenými konstruktory, které se podobají primárním konstruktorům, fungují
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 pro vazby
U typů 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 oba 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 vytvoření vazby Name
znovu.
Age
Je však možné je aktualizovat.
Chování globalizace vázání modelu, data směrování a řetězce dotazů.
Poskytovatel hodnot trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu:
- Zacházejte s hodnotami jako s invariantní kulturou.
- Počítejte s tím, že adresy URL jsou nezávislé na kultuře.
Naproti tomu hodnoty pocházející z dat formuláře podléhají kulturně citlivému převodu. Je to záměrně tak, aby adresy URL byly sdíleny napříč národními prostředími.
Aby poskytovatel hodnoty trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu prošly převodem citlivým na kulturní specifika:
- Dědit z IValueProviderFactory
- Zkopírování kódu z QueryStringValueProviderFactory nebo RouteValueValueProviderFactory
- Nahraďte hodnotu jazykové verze předanou konstruktoru zprostředkovatele hodnot CultureInfo.CurrentCulture.
- Nahraďte výchozí objekt pro vytváření zprostředkovatelů hodnot v možnostech MVC novým objektem:
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
Existuje několik speciálních datových typů, které lze zpracovat vazbou modelu.
IFormFile a IFormFileCollection
Nahraný soubor zahrnutý v požadavku HTTP. Také je podporováno IEnumerable<IFormFile>
pro více souborů.
token pro zrušení
Akce můžou volitelně svázat CancellationToken
jako parametr. Tím se prováže RequestAborted, který signalizuje, kdy je přerušeno připojení, které je základem požadavku HTTP. Akce můžou tento parametr použít ke zrušení dlouhotrvajících asynchronních operací, které se spouští jako součást akcí kontroleru.
Kolekce formulářů
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 ve formátu JSON, XML nebo jiném formátu. K analýze těchto dat používá vazba modelu vstupní formátovací modul , který je nakonfigurovaný pro zpracování konkrétního typu obsahu. Ve výchozím nastavení ASP.NET Core obsahuje vstupní formátovací moduly založené na FORMÁTU JSON pro zpracování dat JSON. 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.
Pro použití zabudovaných XML formátovačů:
V
Program.cs
volejte AddXmlSerializerFormatters nebo AddXmlDataContractSerializerFormatters.builder.Services.AddControllers() .AddXmlSerializerFormatters();
Consumes
Použijte atribut na třídy kontroleru nebo metody akcí, které by měly očekávat KÓD 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. Pokud chcete tento proces přizpůsobit, nakonfigurujte rozhraní API používaná vstupním formátovacím modulem. Tato část popisuje, jak přizpůsobit vstupní formátovací modul založený na System.Text.Json
pro pochopení vlastního typu s názvem ObjectId
.
Představte si následující model, který obsahuje vlastní ObjectId
vlastnost:
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 JsonConverterAttribute atribut na typ. V následujícím příkladu je typ ObjectId
nakonfigurován jako vlastní převaděč s ObjectIdConverter
.
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
Další informace naleznete 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. Ke ModelMetadata
můžete přidat zprostředkovatele podrobností, abyste provedli úpravy . Zprostředkovatelé předdefinovaných podrobností jsou k dispozici pro zakázání vazby nebo ověřování modelu pro zadané typy.
Chcete-li zakázat vazbu modelu u všech modelů určitého typu, přidejte do ExcludeBindingMetadataProviderProgram.cs
. Chcete-li 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í u vlastností zadaného typu, přidejte SuppressChildValidationMetadataProvider do Program.cs
souboru . Chcete-li 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í pořadač modelů a pomocí atributu [ModelBinder]
ho vyberete pro daný cíl. Přečtěte si další informace o vazbě vlastního modelu.
Ruční vazba modelu
Vazbu modelu lze vyvolat ručně pomocí TryUpdateModelAsync metody. Metoda je definována na obou třídách ControllerBase
a PageModel
. Přetížení metod vám umožní zadat předponu a zprostředkovatele hodnot, které chcete použít. Metoda vrátí false
, pokud se nezdaří vazba modelu. 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
je 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í používán s daty z formulářů, řetězci dotazů, a daty trasy. Koncové body webového rozhraní API, které využívají JSON, používají k deserializaci textu požadavku do objektu vstupní formátovací moduly.
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 z poskytovatele hodnot. Získá instanci typu z kontejneru injektáže závislostí. Jejím účelem je poskytnout alternativu k injekci pomocí konstruktoru, pro případy, kdy potřebujete službu pouze, pokud je zavolá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ů:
- Zajistit, aby byl parametr volitelný s hodnotou 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.
Další materiály
Tento článek vysvětluje, co je vazba modelu, jak funguje a jak přizpůsobit její 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 mohou poskytnout klíč záznamu a odeslaná pole formuláře mohou poskytovat hodnoty pro vlastnosti modelu. Psaní kódu pro načtení každé z těchto hodnot a převodu z řetězců na typy .NET by bylo zdlouhavé a náchylné k chybám. Modelová vazba tento proces automatizuje. Systém vazeb modelu:
- Načte data z různých zdrojů, jako jsou údaje o trasách, pole formulářů a řetězce dotazů.
- Poskytuje data pro kontrolery a Razor stránky 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:
- Najde první parametr
GetById
, celé číslo s názvemid
. - Projde dostupné zdroje v požadavku HTTP a ve směrovacích datech najde
id
= "2". - Převede řetězec "2" na celé číslo 2.
- Najde další parametr
GetById
, což je logická hodnota, nazvanýdogsOnly
. - Projde zdroje a v řetězci dotazu najde "DogsOnly=true". Porovnávání názvů není citlivé na písmena.
- Převede řetězec "true" na logickou hodnotu
true
.
Architektura volá metodu GetById
, předává 2 pro parametr id
a true
pro parametr dogsOnly
.
V předchozím příkladu jsou cílové 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 .
Cíle
Vazba modelu se pokouší najít hodnoty pro následující cílové objekty:
- 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, aby byla vazba modelu zaměřena na tuto vlastnost.
public class EditModel : InstructorsPageModel
{
[BindProperty]
public Instructor Instructor { get; set; }
Atribut [BindProperties]
K dispozici v ASP.NET Core 2.1 nebo novějším. 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ázány pro požadavky HTTP GET. Obvykle stačí k požadavku GET parametr ID záznamu. ID záznamu slouží k vyhledání položky v databázi. Proto není nutné svázat vlastnost, která obsahuje instanci modelu. Ve scénářích, ve kterých chcete 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:
- Pole formuláře
- Text požadavku (pro kontrolery, které mají atribut [ApiController].)
- Údaje o trase
- Parametry dotazového řetězce
- 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ěrovací data a řetězcové hodnoty dotazu se používají jenom pro jednoduché typy.
- Nahrané soubory jsou vázány pouze na cílové typy, které implementují
IFormFile
neboIEnumerable<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 polí publikovaného 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), jak je znázorněno 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 hlavička s pomlčkou v názvu, jak je znázorněno 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č. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
Při [FromBody]
použití u parametru komplexního 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 těla:
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]
je ignorován. - Vlastnost
Breed
není naplněna parametrem řetězce dotazu.
Vstupní formátovací moduly čtou pouze tělo a nerozumí atributům zdroje vazby. Pokud je v těle nalezena vhodná hodnota, tato hodnota se použije k naplnění Breed
atributu.
Nepoužívejte [FromBody]
na více než jeden parametr v rámci jedné akce. Jakmile stream požadavku načte vstupní formátovací modul, nebude už k dispozici ke čtení pro vazbu dalších [FromBody]
parametrů.
Další zdroje
Zdrojová data jsou poskytována systému modelového propojení 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 souborů cookie nebo stavu relace. 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.ConfigureServices
souboru.
Ukázková aplikace obsahuje zprostředkovatele hodnot a příklad továrny, který získává hodnoty ze souborů cookie. 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, které mohou být null, jsou nastaveny na
null
. - Typy hodnot, které nemohou mít hodnotu null, jsou nastaveny na
default(T)
. Například parametrint id
je nastaven na hodnotu 0. - V případě komplexních typů vytvoří vazba modelu instanci pomocí výchozího konstruktoru bez nastavení vlastností.
- Pole jsou nastavena na
Array.Empty<T>()
, kromě toho, žebyte[]
pole jsou nastavena nanull
.
Pokud by stav modelu měl být 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í platí pro vazbu modelu z publikovaných dat formuláře, ne pro data JSON 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 najde zdroj, ale nejde ho 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, výsledkem neplatného stavu modelu je automatická odpověď HTTP 400.
Na Razor stránce znovu zobrazte chybovou zprávu.
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
_instructorsInMemoryStore.Add(Instructor);
return RedirectToPage("./Index");
}
Ověření na straně klienta zachytává nejvíce chybná data, 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ží chybná data do datum nástupu 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 převést vlastnost modelu na řetězec a provést manuální převod dat.
Stejná strategie se doporučuje, pokud nechcete, aby chyby převodu typů způsobily chyby stavu modelu. V takovém případě nastavte vlastnost modelu jako řetězec.
Jednoduché typy
Mezi jednoduché typy, na které může pořadač modelů převést zdrojové řetězce, patří následující:
- Logická hodnota
- Bajt, SByte
- Znak
- Datum a čas
- DateTimeOffset
- Desetinné číslo
- Dvojité
- Výčet
- Identifikátor GUID
- Int16, Int32, Int64
- Jednoduchý
- Časový rozsah
- UInt16, UInt32, UInt64
- URI
- Verze
Komplexní typy
Komplexní typ musí mít veřejné výchozí konstruktor a veřejné zapisovatelné vlastnosti pro vytvoření vazby. Když dojde k vytvoření vazby modelu, vytvoří se instance třídy pomocí veřejného výchozího konstruktoru.
Pro každou vlastnost komplexního typu vazba modelu prohledává zdroje pro vzor názvu prefix.property_name. Pokud se nic nenajde, hledá jenom property_name bez předpony.
Pro vazbu na parametr je předpona název parametru. Pro vazbu na PageModel
veřejnou vlastnost je předpona název 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; }
}
Předpona = 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á procházením zdrojů klíče instructorToUpdate.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Prefix = 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á procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Vlastní předpona
Pokud je model, který má být vázán, parametr s názvem instructorToUpdate
a Bind
atribut určuje Instructor
jako předponu:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
Vazba modelu začíná procházením zdrojů klíče Instructor.ID
. Pokud se nenajde, vyhledá ID
bez předpony.
Atributy pro cíle komplexního typu
Pro řízení vazby modelu komplexních typů je k dispozici několik předdefinovaných atributů:
[Bind]
[BindRequired]
[BindNever]
Varování
Tyto atributy ovlivňují vazbu modelu, když jsou zdrojem hodnot data odeslaná formulářem. Nemají vliv na vstupní formátovací moduly, které zpracovávají odeslaná těla požadavků typu JSON a XML. Vstupní formátovací moduly jsou vysvětleny dále v tomto článku.
[Bind] – atribut
Lze použít na třídu nebo parametr metody. Určuje, které vlastnosti modelu mají být zahrnuty do vazby modelu.
[Bind]
nemá žádný vliv na vstupní formátovací moduly.
V následujícím příkladu jsou vázány pouze zadané vlastnosti Instructor
modelu, pokud je volána jakákoli obslužná rutina nebo metoda akce:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
V následujícím příkladu jsou při zavolání metody Instructor
vázány pouze zadané vlastnosti modelu OnPost
.
[HttpPost]
public IActionResult OnPost([Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
Atribut [Bind]
lze použít k ochraně proti nadměrnému umístění ve scénářích vytváření . Nefunguje dobře ve scénářích úprav, protože vyloučené vlastnosti jsou nastavené na hodnotu null nebo výchozí hodnotu, místo aby zůstaly beze změny. Pro ochranu před nadměrném umístěním se místo atributu [Bind]
doporučuje zobrazit modely. Další informace naleznete v tématu Bezpečnostní poznámka o nadměrném příspěvku.
Atribut [ModelBinder]
ModelBinderAttribute lze použít u typů, vlastností nebo parametrů. Umožňuje zadat typ vazebníka modelu použitého pro navázání 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, ne 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, ne na parametry metody. Zabraňuje 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 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 vytvoření vazby parametru nebo vlastnosti s názvem
index
neboIndex
pokud sousedí s hodnotou kolekce. Vazba modelu se pokusí použítindex
jako index pro kolekci, což může způsobit nesprávnou vazbu. Představte si například následující akci:public IActionResult Post(string index, List<Product> products)
V předchozím kódu se parametr řetězce dotazu
index
sváže s parametremindex
metody a rovněž se použije k vazbě kolekce produktů. Přejmenování parametru nebo použití atributuindex
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í příkladové formáty předává modelová vazba 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 číslony 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 indexy 0 a 2 místo 0 a 1, druhá položka se ignoruje.
Slovníky
V případě Dictionary
cílů vazba modelu hledá 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
Dictionary<int, string>
nazvánselectedCourses
:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)
Data publikovaného formuláře nebo řetězce dotazu můžou 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 ukázkové formáty uvedené výše předá vazba modelu slovník obsahující dvě položky parametru
selectedCourses
:- selectedCourses["1050"]="Chemie"
- selectedCourses["2000"]="Ekonomie"
Vazby konstruktoru a typy záznamů
Vazba modelu vyžaduje, aby složité typy měly konstruktor bez parametrů.
System.Text.Json
i Newtonsoft.Json
vstupní formátory podporují deserializaci tříd, které nemají bezparametrický konstruktor.
C# 9 představuje typy záznamů, které představují skvělý způsob, jak stručně znázorňovat data v síti. ASP.NET Core přidává podporu pro vazbu 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
<label>Name: <input asp-for="Name" /></label>
...
<label>Age: <input asp-for="Age" /></label>
Při ověřování typů záznamů modul runtime vyhledává metadata vazby a ověřování, a to konkrétně u parametrů, nikoli u vlastností.
Architektura umožňuje vazbu na typy 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:
- Být typem záznamu.
- Má 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 velikostí písmen.
POCOs bez konstruktorů bez parametrů
POCOs, které nemají bezparametrové konstruktory, nelze napojit.
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ě napsanými konstruktory
Typy záznamů s ručně vytvořenými konstruktory, které se podobají primárním konstruktorům, fungují
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 pro vazby
U typů 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 oba 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é je aktualizovat.
Chování globalizace vázání modelu, data směrování a řetězce dotazů.
Poskytovatel hodnot trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu:
- Zacházejte s hodnotami jako s invariantní kulturou.
- Počítejte s tím, že adresy URL jsou nezávislé na kultuře.
Naproti tomu hodnoty pocházející z dat formuláře podléhají kulturně citlivému převodu. Je to záměrně tak, aby adresy URL byly sdíleny napříč národními prostředími.
Aby poskytovatel hodnoty trasy ASP.NET Core a poskytovatel hodnot řetězce dotazu prošly převodem citlivým na kulturní specifika:
- Dědit z IValueProviderFactory
- Zkopírování kódu z QueryStringValueProviderFactory nebo RouteValueValueProviderFactory
- Nahraďte hodnotu jazykové verze předanou konstruktoru zprostředkovatele hodnot CultureInfo.CurrentCulture.
- Nahraďte výchozí objekt pro vytváření zprostředkovatelů hodnot v možnostech MVC novým objektem:
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
Existuje několik speciálních datových typů, které lze zpracovat vazbou modelu.
IFormFile a IFormFileCollection
Nahraný soubor zahrnutý v požadavku HTTP. Také je podporováno IEnumerable<IFormFile>
pro více souborů.
token pro zrušení
Akce můžou volitelně svázat CancellationToken
jako parametr. Tím se prováže RequestAborted, který signalizuje, kdy je přerušeno připojení, které je základem požadavku HTTP. Akce můžou tento parametr použít ke zrušení dlouhotrvajících asynchronních operací, které se spouští jako součást akcí kontroleru.
Kolekce formulářů
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 ve formátu JSON, XML nebo jiném formátu. K analýze těchto dat používá vazba modelu vstupní formátovací modul , který je nakonfigurovaný pro zpracování konkrétního typu obsahu. Ve výchozím nastavení ASP.NET Core obsahuje vstupní formátovací moduly založené na FORMÁTU JSON pro zpracování dat JSON. 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.
Pro použití zabudovaných XML formátovačů:
Microsoft.AspNetCore.Mvc.Formatters.Xml
Nainstalujte balíček NuGet.V
Startup.ConfigureServices
volejte AddXmlSerializerFormatters 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 akcí, které by měly očekávat KÓD 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. Pokud chcete tento proces přizpůsobit, nakonfigurujte rozhraní API používaná vstupním formátovacím modulem. Tato část popisuje, jak přizpůsobit vstupní formátovací modul založený na System.Text.Json
pro pochopení vlastního typu s názvem ObjectId
.
Představte si 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 JsonConverterAttribute atribut na typ. V následujícím příkladu je typ ObjectId
nakonfigurován jako vlastní převaděč s ObjectIdConverter
.
[JsonConverter(typeof(ObjectIdConverter))]
public struct ObjectId
{
public ObjectId(int id) =>
Id = id;
public int Id { get; }
}
Další informace naleznete 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. Ke ModelMetadata
můžete přidat zprostředkovatele podrobností, abyste provedli úpravy . Zprostředkovatelé předdefinovaných podrobností jsou k dispozici pro zakázání vazby nebo ověřování modelu pro zadané typy.
Chcete-li zakázat vazbu modelu u všech modelů určitého typu, přidejte do ExcludeBindingMetadataProviderStartup.ConfigureServices
. Chcete-li 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í u vlastností zadaného typu, přidejte SuppressChildValidationMetadataProvider do Startup.ConfigureServices
souboru . Chcete-li 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í pořadač modelů a pomocí atributu [ModelBinder]
ho vyberete pro daný cíl. Přečtěte si další informace o vazbě vlastního modelu.
Ruční vazba modelu
Vazbu modelu lze vyvolat ručně pomocí TryUpdateModelAsync metody. Metoda je definována na obou třídách ControllerBase
a PageModel
. Přetížení metod vám umožní zadat předponu a zprostředkovatele hodnot, které chcete použít. Metoda vrátí false
, pokud se nezdaří vazba 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
je 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í používán s daty z formulářů, řetězci dotazů, a daty trasy. Koncové body webového rozhraní API, které využívají JSON, používají k deserializaci textu požadavku do objektu vstupní formátovací moduly.
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 z poskytovatele hodnot. Získá instanci typu z kontejneru injektáže závislostí. Jejím účelem je poskytnout alternativu k injekci pomocí konstruktoru, pro případy, kdy potřebujete službu pouze, pokud je zavolána konkrétní metoda.