Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Note
Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.
Warning
A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. A jelen cikk .NET 9-es verzióját lásd az aktuális kiadásért .
Ez a cikk bemutatja, hogy mi a modellkötés, hogyan működik, és hogyan szabhatja testre a viselkedését.
Mi az a modellkötés?
A vezérlők és Razor lapok HTTP-kérelmekből származó adatokkal dolgoznak. Az útvonaladatok például megadhatnak egy rekordkulcsot, a közzétett űrlapmezők pedig értékeket adhatnak a modell tulajdonságaihoz. A kód megírása ezeknek az értékeknek a lekéréséhez és a sztringekből .NET-típusokká való konvertálásához fárasztó és hibalehetőségekkel járna. A modellkötés automatizálja ezt a folyamatot. A modellkötési rendszer:
- Adatokat kér le különböző forrásokból, például útvonaladatokból, űrlapmezőkből és lekérdezési sztringekből.
- Az adatokat a vezérlőknek és Razor oldalaknak biztosítja a metódusparaméterek és a nyilvános tulajdonságok útján.
- A sztringadatokat .NET-típusokká alakítja.
- Frissíti az összetett típusok tulajdonságait.
Example
Tegyük fel, hogy a következő műveleti módszerrel rendelkezik:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Az alkalmazás a következő URL-címmel kap egy kérést:
https://contoso.com/api/pets/2?DogsOnly=true
A modellkötés a következő lépéseken megy keresztül, miután az útválasztási rendszer kiválasztotta a műveletmetódust:
- Megkeresi a
GetByIdelső paraméterét , amely egyidnevű egész szám. - Megvizsgálja a HTTP-kérelemben elérhető forrásokat, és megkeresi a
id= "2" értéket az útvonaladatokban. - A "2" sztringet 2 egész számmá alakítja.
- Megkeresi a
GetByIdkövetkező paraméterét , egydogsOnlynevű logikai értéket. - Megvizsgálja a forrásokat, és megkeresi a "DogsOnly=true" kifejezést a lekérdezési sztringben. A névegyeztetés nem érzékeny a kis- és nagybetűkre.
- Az "true" sztringet booleán típusú
trueértékké alakítja át.
A keretrendszer ezután meghívja a GetById metódust, és a 2-t adja át a id paraméternek, valamint true-t adja át a dogsOnly paraméternek.
Az előző példában a modellkötési célok olyan metódusparaméterek, melyek egyszerű típusok. A célok egy összetett típus tulajdonságai is lehetnek. Az egyes tulajdonságok sikeres kötése után modellérvényesítési történik az adott tulajdonsághoz. A modellhez kötött adatok nyilvántartása, valamint bármely kötési vagy érvényesítési hiba a ControllerBase.ModelState vagy PageModel.ModelStatetárolva van. Annak kiderítéséhez, hogy a folyamat sikeres volt-e, az alkalmazás ellenőrzi a ModelState.IsValid jelzőt.
Targets
A modellkötés a következő típusú célok értékeit próbálja megtalálni:
- Annak a vezérlőműveleti metódusnak a paraméterei, amelyekre a kérések irányítva lesznek.
- Azon Razor Pages-kezelő metódus paraméterei, amelyekhez a kérések irányítva lesznek.
- Egy vezérlő vagy
PageModelosztály nyilvános tulajdonságai, ha az attribútumok meg vannak adva.
[BindProperty] attribútum
Egy vezérlő vagy PageModel osztály nyilvános tulajdonságára alkalmazható, hogy a modellkötés a tulajdonságot célozza:
public class EditModel : PageModel
{
[BindProperty]
public Instructor? Instructor { get; set; }
// ...
}
[BindProperties] attribútum
Egy vezérlőre vagy PageModel osztályra alkalmazható, hogy a modellkötés az osztály összes nyilvános tulajdonságát megcélzhassa:
[BindProperties]
public class CreateModel : PageModel
{
public Instructor? Instructor { get; set; }
// ...
}
Modellkötés HTTP GET-kérelmekhez
Alapértelmezés szerint a http GET-kérések nem kötik a tulajdonságokat. A GET-kéréshez általában csak egy rekordazonosító paraméter szükséges. A rekordazonosítóval megkereshető az elem az adatbázisban. Ezért nincs szükség olyan tulajdonság kötésére, amely a modell egy példányát tartalmazza. Olyan esetekben, amikor a GET-kérelmekből származó adatokhoz kötött tulajdonságokat szeretne, állítsa a SupportsGet tulajdonságot true:
[BindProperty(Name = "ai_user", SupportsGet = true)]
public string? ApplicationInsightsCookie { get; set; }
Egyszerű és összetett modellkötési típusok
A modellkötés meghatározott definíciókat használ az általa használt típusokhoz. A egyszerű típus egyetlen sztringből konvertálódik TypeConverter vagy TryParse metódus használatával. A összetett típus több bemeneti értékből konvertálódik. A keretrendszer egy TypeConverter vagy TryParsemegléte alapján határozza meg a különbséget . Javasoljuk, hogy hozzon létre egy típuskonvertert, vagy használjon TryParse egy stringSomeType átalakításhoz, amely nem igényel külső erőforrásokat vagy több bemenetet.
Sources
A modellkötés alapértelmezés szerint kulcs-érték párok formájában kéri le az adatokat egy HTTP-kérelem következő forrásaiból:
- Űrlapmezők
- A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
- Útvonal adatok
- Lekérdezési sztringparaméterek
- Feltöltött fájlok
Minden célparaméter vagy tulajdonság esetében a forrásokat az előző listában megadott sorrendben ellenőrzi a rendszer. Van néhány kivétel:
- Az útvonaladatok és a lekérdezési sztringértékek csak egyszerű típusokhoz használhatók.
- A feltöltött fájlok csak olyan céltípusokhoz vannak kötve, amelyek
IFormFilevagyIEnumerable<IFormFile>implementálnak.
Ha az alapértelmezett forrás helytelen, használja az alábbi attribútumok egyikét a forrás megadásához:
-
[FromQuery]– Lekéri a lekérdezési sztring értékeit. -
[FromRoute]– Lekéri az útvonaladatok értékeit. -
[FromForm]– Lekéri a beküldött űrlapmezők értékeit. -
[FromBody]– Lekéri az értékeket a kérelem törzséből. -
[FromHeader]– HTTP-fejlécekből származó értékeket kap.
Ezek az attribútumok:
A modelltulajdonságok egyenként vannak hozzáadva a modellosztályhoz, nem pedig a modellosztályhoz, ahogyan az alábbi példában látható:
public class Instructor { public int Id { get; set; } [FromQuery(Name = "Note")] public string? NoteFromQueryString { get; set; } // ... }Igény szerint elfogadhat egy modellnévértéket a konstruktorban. Ez a beállítás abban az esetben van megadva, ha a tulajdonság neve nem egyezik meg a kérelemben szereplő értékkel. A kérés értéke lehet például egy fejléc, amelynek nevében egy kötőjel szerepel, ahogyan az alábbi példában is látható:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] attribútum
Alkalmazza a [FromBody] attribútumot egy paraméterre, hogy a tulajdonságait egy HTTP-kérés törzséből töltse ki. A ASP.NET Core futtatókörnyezet egy bemeneti formázónak delegálja a törzs olvasásának felelősségét. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
Ha [FromBody] komplex típusú paraméterre van alkalmazva, a rendszer figyelmen kívül hagyja a tulajdonságokra alkalmazott kötési forrásattribútumokat. Az alábbi Create művelet például azt határozza meg, hogy a pet paramétere ki legyen töltve a törzsből:
public ActionResult<Pet> Create([FromBody] Pet pet)
A Pet osztály azt határozza meg, hogy a Breed tulajdonsága egy lekérdezési sztringparaméterből legyen feltöltve:
public class Pet
{
public string Name { get; set; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
Az előző példában:
- A
[FromQuery]attribútum figyelmen kívül lesz hagyva. - A
Breedtulajdonság nincs kitöltve lekérdezési sztringparaméterből.
A bemeneti formázók csak a törzset olvassák, és nem értik a kötés forrásattribútumait. Ha a törzsben talál egy megfelelő értéket, a rendszer ezt az értéket használja a Breed tulajdonság feltöltéséhez.
Ne alkalmazza a [FromBody] műveletmetódusonként egynél több paraméterre. Miután a kérelemfolyamot beolvassa egy bemeneti formázó, már nem olvasható újra más [FromBody] paraméterek kötéséhez.
További források
A forrásadatokat értékszolgáltatókadják meg a modellkötési rendszernek. Írhat és regisztrálhat olyan egyéni értékszolgáltatókat, amelyek más forrásokból származó modellkötési adatokat kérnek le. Előfordulhat például, hogy cookie-kból vagy munkamenet-állapotból szeretne adatokat. Adatok lekérése új forrásból:
- Hozzon létre egy
IValueProvidermegvalósító osztályt. - Hozzon létre egy
IValueProviderFactorymegvalósító osztályt. - Regisztrálja a gyári osztályt a
Program.cs-ban.
A minta egy értéket szolgáltató és egy generátor példát tartalmaz, amely a cookie-kból kap értékeket. A Program.csegyéni értékszolgáltató gyárainak regisztrálása:
builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});
Az előző kód az egyéni értékszolgáltatót az összes beépített értékszolgáltató után helyezi el. Ahhoz, hogy ez legyen az első a listában, Insert(0, new CookieValueProviderFactory())helyett hívja meg Add.
Nincs forrás egy modelltulajdonsághoz
Alapértelmezés szerint nem jön létre modellállapot-hiba, ha nem található érték egy modelltulajdonsághoz. A tulajdonság értéke null vagy alapértelmezett érték:
- A null értékű egyszerű típusok
nullértékre vannak állítva. - A nem null értékű értéktípusok értéke be van állítva
default(T). Egyint idparaméter például 0 értékre van állítva. - Összetett típusok esetén a modellkötés az alapértelmezett konstruktor használatával hoz létre egy példányt tulajdonságok megadása nélkül.
- A tömbök
Array.Empty<T>()értékre vannak beállítva, kivéve, hogy abyte[]tömböknullértékre vannak beállítva.
Ha a modell állapotát érvényteleníteni kell, ha nem található semmi a modelltulajdonság űrlapmezőiben, használja a [BindRequired] attribútumot.
Vegye figyelembe, hogy ez a [BindRequired] viselkedés a közzétett űrlapadatokból származó modellkötésekre vonatkozik, nem pedig a kérelem törzsében lévő JSON- vagy XML-adatokból. Az igénylés törzsadatait a bemeneti formázókkezelik.
Típuskonvertálási hibák
Ha talál egy forrást, de nem konvertálható céltípussá, a modell állapota érvénytelenként van megjelölve. A célparaméter vagy tulajdonság null értékűre vagy alapértelmezett értékre van állítva az előző szakaszban leírtak szerint.
A [ApiController] attribútummal rendelkező API-vezérlőben az érvénytelen modellállapot automatikus HTTP 400-választ eredményez.
Razor lapon jelenítse meg újra a lapot egy hibaüzenettel:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
Ha az előző kód visszajelzi a lapot, az érvénytelen bemenet nem jelenik meg az űrlapmezőben. Ennek az az oka, hogy a modelltulajdonság null értékűre vagy alapértelmezett értékre lett beállítva. Az érvénytelen bemenet megjelenik egy hibaüzenetben. Ha újra meg szeretné jeleníteni a hibás adatokat az űrlapmezőben, fontolja meg, hogy a modell tulajdonságát sztringként használja, és az adatkonvertálást manuálisan végezze el.
Ugyanez a stratégia akkor ajánlott, ha nem szeretné, hogy a típuskonvertálási hibák modellállapot-hibákat eredményeznek. Ebben az esetben változtassa a modell tulajdonságát stringgé.
Egyszerű típusok
Az egyszerű és összetett típusok magyarázatáért lásd a modellkötési és fejezeteket.
A modellkötő által forrássztringekké átalakítható egyszerű típusok a következők:
- Boolean
- Bájt, SByte
- Char
- DateOnly
- DateTime
- DateTimeOffset
- Decimal
- Double
- Enum
- Guid
- Int16, Int32, Int64
- Single
- TimeOnly
- TimeSpan
- UInt16, UInt32, UInt64
- Uri
- Version
Kötés a IParsable<T>.TryParse
A IParsable<TSelf>.TryParse API támogatja a kötésvezérlő műveleti paramétereinek értékeit:
public static bool TryParse (string? s, IFormatProvider? provider, out TSelf result);
Az alábbi DateRange osztály implementálja a IParsable<TSelf> a dátumtartomány kötésének támogatásához:
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;
}
}
Az előző kód:
- Két dátumot ábrázoló sztringet konvertál
DateRangeobjektummá - A modellkötő a
IParsable<TSelf>.TryParsemetódust használja aDateRangekötéséhez.
A következő vezérlőművelet a DateRange osztályt használja egy dátumtartomány kötéséhez:
// 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);
}
Az alábbi Locale osztály IParsable<TSelf> valósít meg a CultureInfokötésének támogatásához:
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;
}
}
}
A következő vezérlőművelet a Locale osztályt használja egy CultureInfo sztring kötéséhez:
// 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);
}
Az alábbi vezérlőművelet a DateRange és Locale osztályokkal köti össze a dátumtartományt 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);
}
A API-mintaalkalmazás a GitHubon egy korábbi példát jelenít meg egy API-vezérlőhöz.
Kötés a TryParse
A TryParse API támogatja a kötésvezérlő műveleti paramétereinek értékeit:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
IParsable<T>.TryParse a paraméterkötés ajánlott megközelítése, mert a TryParseellentétben ez nem függ a tükröződéstől.
Az alábbi DateRangeTP osztály implementálja a 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;
}
}
A következő vezérlőművelet a DateRangeTP osztályt használja egy dátumtartomány kötéséhez:
// 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);
}
Összetett típusok
Egy összetett típusnak nyilvános alapértelmezett konstruktorsal és nyilvános írható tulajdonságokkal kell rendelkeznie a kötéshez. Modellkötés esetén az osztály példányosítása a nyilvános alapértelmezett konstruktor használatával történik.
Az összetett típus minden tulajdonsága esetében a modell kötés átnézi a forrásokat aprefix.property_namenévminta szerint. Ha semmi sem található, csak property_name keres az előtag nélkül. Az előtag használatára vonatkozó döntés nem tulajdonságonként történik. Ha például egy ?Instructor.Id=100&Name=footartalmazó lekérdezés OnGet(Instructor instructor)metódushoz van kötve, az eredményként kapott Instructor típusú objektum a következőket tartalmazza:
-
Id100értékre van állítva. -
Namenullértékre van állítva. A modellkötésInstructor.Namevár, mert az előző lekérdezési paraméterbenInstructor.Idhasználták.
Note
A .NET referenciaforrásra mutató dokumentációs hivatkozások általában betöltik az adattár alapértelmezett ágát, amely a .NET következő kiadásának aktuális fejlesztését jelöli. Egy adott kiadás címkéjének kiválasztásához használja az Ágak vagy címkék közötti váltás legördülő listát. További információ: A ASP.NET Core-forráskód (dotnet/AspNetCore.Docs #26205) verziócímkéjének kiválasztása.
A paraméterhez való kötésnél az előtag a paraméter neve. Egy PageModel nevű nyilvános tulajdonsághoz való kötés esetén az előtag a tulajdonság neve. Egyes attribútumok Prefix tulajdonságot használnak, amelyekkel felülbírálhatja a paraméter vagy a tulajdonságnév alapértelmezett használatát.
Tegyük fel például, hogy az összetett típus a következő Instructor osztály:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Előtag = paraméternév
Ha a kötendő modell egy instructorToUpdatenevű paraméter:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
A modellkötés a kulcs instructorToUpdate.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Előtag = tulajdonságnév
Ha a kötendő modell a vezérlő Instructor nevű tulajdonsága vagy a PageModel osztály:
[BindProperty]
public Instructor Instructor { get; set; }
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Egyéni előtag
Ha a kötendő modell egy instructorToUpdate nevű paraméter, és egy Bind attribútum Instructor határoz meg előtagként:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Attribútumok összetett típusú célokhoz
Összetett típusok modellkötésének szabályozásához számos beépített attribútum érhető el:
Warning
Ezek az attribútumok hatással vannak a modellkötésre, ha a közzétett űrlapadatok az értékek forrása. Nincsenek hatással a bemeneti formázók működésére, melyek feldolgozzák a közzétett JSON- és XML-kérelemtörzseket. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
[Kötés] attribútum
Alkalmazható osztályra vagy metódusparaméterre. Meghatározza, hogy a modell mely tulajdonságait kell szerepeltetni a modellkötésben.
[Bind] nem hatással a bemeneti formázókra.
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve, amikor bármely kezelőt vagy műveletmetódust meghívnak:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve a OnPost metódus meghívásakor:
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
A [Bind] attribútum használható a forgatókönyvek létrehozásakor a túlzott adatküldés elleni védelemre. Szerkesztési forgatókönyvekben nem működik jól, mert a kizárt tulajdonságok értéke null vagy alapértelmezett érték, ahelyett, hogy változatlan marad. A túlpostolás elleni védelem érdekében a [Bind] attribútum helyett a nézetmodellek használata ajánlott. További információ: biztonsági megjegyzés atúlpostolásáról.
[ModelBinder] attribútum
ModelBinderAttribute alkalmazhatók típusokra, tulajdonságokra vagy paraméterekre. Lehetővé teszi az adott példány vagy típus kötéséhez használt modellkötő típusának megadását. Például:
[HttpPost]
public IActionResult OnPost(
[ModelBinder<MyInstructorModelBinder>] Instructor instructor)
A [ModelBinder] attribútum egy tulajdonság vagy paraméter nevének módosítására is használható modellkötés esetén:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
// ...
}
[BindRequired] attribútum
Ha a modell tulajdonságához nem lehetséges a kötés, a modellkötés modellállapot-hibát ad hozzá. Íme egy példa:
public class InstructorBindRequired
{
// ...
[BindRequired]
public DateTime HireDate { get; set; }
}
Lásd még a [Required] attribútumának ismertetését.
[BindNever] attribútum
Alkalmazható tulajdonságra vagy típusra. Megakadályozza azt, hogy a modell kötési folyamata beállítsa a modell tulajdonságát. Típusra alkalmazva a modellkötési rendszer kizárja a típus által definiált összes tulajdonságot. Íme egy példa:
public class InstructorBindNever
{
[BindNever]
public int Id { get; set; }
// ...
}
Collections
Az egyszerű típusok gyűjteményét tartalmazó célok esetében a modellkötés a parameter_name vagy property_nameegyezéseket keres. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a kötendő paraméter egy
selectedCoursesnevű tömb:public IActionResult OnPost(int? id, int[] selectedCourses)Az űrlap- vagy lekérdezési sztringadatok az alábbi formátumok egyikében lehetnek:
selectedCourses=1050&selectedCourses=2000selectedCourses[0]=1050&selectedCourses[1]=2000[0]=1050&[1]=2000selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b[a]=1050&[b]=2000&index=a&index=bKerülje egy
indexvagyIndexnevű paraméter vagy tulajdonság kötését, ha az egy gyűjteményérték mellett található. A modellkötés megpróbálja aindex-t gyűjteményindexként használni, ami helytelen kötéshez vezethet. Vegyük például a következő műveletet:public IActionResult Post(string index, List<Product> products)Az előző kódban a
indexlekérdezési sztring paraméter aindexmetódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi aindexparamétert, vagy modellkötési attribútumot használ a kötés konfigurálásához, elkerüli ezt a problémát:public IActionResult Post(string productIndex, List<Product> products)A következő formátum csak űrlapadatokban támogatott:
selectedCourses[]=1050&selectedCourses[]=2000Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a
selectedCoursesparaméternek:- selectedCourses[0]=1050
- selectedCourses[1]=2000
Alsó indexszámokat használó adatformátumoknak (... [0] ... [1] ...) meg kell győződniük arról, hogy nullától kezdve egymás után vannak számozva. Ha van rés az alsó indexszámozásban, a rendszer figyelmen kívül hagyja a rést követő összes elemet. Ha például az alsó indexek 0 és 1 helyett 0 és 2, akkor a második elemet figyelmen kívül hagyják.
Dictionaries
A Dictionary-célok esetében a modellkötés a parameter_name vagy property_nametalálatokat keresi. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a célparaméter egy
Dictionary<int, string>nevűselectedCourses:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)A közzétett űrlap- vagy lekérdezési sztringadatok az alábbi példák egyikéhez hasonlóan nézhetnek ki:
selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics[1050]=Chemistry&selectedCourses[2000]=EconomicsselectedCourses[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=EconomicsAz összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a
selectedCoursesparaméternek:- selectedCourses["1050"]="Chemistry"
- selectedCourses["2000"]="Economics"
Konstruktorkötés és rekordtípusok
A modellkötéshez az összetett típusok paraméter nélküli konstruktort igényelnek. Mind System.Text.Json, mind Newtonsoft.Json alapú bemeneti formázók támogatják a paraméter nélküli konstruktor nélküli osztályok deszerializálását.
A rekordtípusok kiválóan alkalmasak arra, hogy tömören ábrázolják az adatokat a hálózaton. ASP.NET Core egyetlen konstruktor használatával támogatja a modellkötést és a rekordtípusok érvényesítését:
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>
Rekordtípusok ellenőrzésekor a futtatókörnyezet a tulajdonságok helyett a paramétereken keres kötési és érvényesítési metaadatokat.
A keretrendszer lehetővé teszi a rekordtípusok kötését és érvényesítését:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Az előző működéshez a típusnak a következőnek kell lennie:
- Legyen rekordtípus.
- Pontosan egy nyilvános konstruktor.
- Olyan paramétereket tartalmaz, amelyek azonos nevű és típusú tulajdonsággal rendelkeznek. A nevek kis- és nagybetűk szerint nem különbözhetnek.
Paraméter nélküli konstruktorok nélküli POCO-k
Azok a POCO-k, amelyek nem rendelkeznek paraméter nélküli konstruktorokkal, nem köthetők.
Az alábbi kód kivételt eredményez, amely szerint a típusnak paraméter nélküli konstruktort kell tartalmaznia:
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)
{
}
}
Rekordtípusok manuálisan létrehozott konstruktorokkal
Az elsődleges konstruktorokhoz hasonló, manuálisan létrehozott konstruktorokkal rendelkező rekordtípusok működnek
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; }
}
Rekordtípusok, érvényesítési és kötési metaadatok
Rekordtípusok esetében a paraméterek érvényesítési és kötési metaadatait használja a rendszer. A tulajdonságok metaadatai figyelmen kívül lesznek hagyva
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; }
}
Érvényesítés és metaadatok
Az ellenőrzés metaadatokat használ a paraméteren, de a tulajdonság használatával olvassa be az értéket. Az elsődleges konstruktorok esetében a kettő azonos lenne. Vannak azonban módszerek a legyőzésére:
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; }
}
A TryUpdateModel nem frissíti a rekordtípus paramétereit
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
Ebben az esetben az MVC nem próbálja meg újra megkötni Name. A Age azonban frissíthető
Modellkötés útvonaladatainak és lekérdezési sztringjeinek globalizációs viselkedése
A ASP.NET Fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató:
- Értékeket invariáns kultúraként kezelni.
- Arra számít, hogy az URL-címek kulturális invariánsak.
Ezzel szemben az űrlapadatokból származó értékek kultúraérzékeny átalakításon mennek keresztül. Az URL-címek szándékosan úgy vannak kialakítva, hogy megoszthatóak legyenek az egyes területek között.
A ASP.NET fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató kulturális szempontból érzékeny átalakításon megy keresztül:
- Származzon a IValueProviderFactory-ból
- Másolja az alábbi kódot QueryStringValueProviderFactory vagy RouteValueValueProviderFactory
- Cserélje le az értékszolgáltató konstruktorának átadott kulturálisCultureInfo.CurrentCulture
- Cserélje le az alapértelmezett értékszolgáltató gyárat az MVC-beállításokban az Ön új értékszolgáltatójára.
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ális adattípusok
Vannak speciális adattípusok, amelyeket a modellkötés képes kezelni.
IFormFile és IFormFileCollection
A HTTP-kérelemben szereplő feltöltött fájl. Támogatott a IEnumerable<IFormFile> több fájlhoz is.
CancellationToken
A műveletek opcionálisan paraméterként köthetnek egy CancellationToken. Ez köti RequestAborted, amely jelzi, ha a HTTP-kérés alapjául szolgáló kapcsolat megszakad. A műveletek ezzel a paraméterrel megszakíthatják a vezérlőműveletek részeként végrehajtott hosszú ideig futó aszinkron műveleteket.
FormCollection
Az összes érték lekérésére szolgál a közzétett űrlapadatokból.
Bemeneti formázók
A kérelem törzsében lévő adatok lehetnek JSON-, XML- vagy egyéb formátumúak. Az adatok elemzéséhez a modellkötés egy bemeneti formázó használ, amely egy adott tartalomtípus kezelésére van konfigurálva. Alapértelmezés szerint a ASP.NET Core JSON-alapú bemeneti formázókat tartalmaz a JSON-adatok System.Text.Jsonkezeléséhez. Más tartalomtípusokhoz más formátumkészítőket is hozzáadhat.
Az alapértelmezett JSON bemeneti formátumoló a következő módszerrel konfigurálható AddJsonOptions :
builder.Services.AddControllers().AddJsonOptions(options =>
{
// Configure property naming policy (camelCase)
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
// Add enum converter to serialize enums as strings
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
// Configure other JSON options
options.JsonSerializerOptions.WriteIndented = true;
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
});
Gyakori konfigurációs lehetőségek a következők:
- Tulajdonságelnevezési szabályzat – CamelCase vagy más elnevezési konvenciók konfigurálása
- Enum-konverterek – Az enumok szerializálása sztringként
- Egyéni konverterek – Típusspecifikus szerializálási logika hozzáadása
ASP.NET Core a attribútum alapján választja ki a bemeneti formázókat. Ha nincs attribútum, akkor a Content-Type fejlécet használja.
A beépített XML-bemeneti formázók használata:
Hívja a
Program.cs, AddXmlSerializerFormatters vagy AddXmlDataContractSerializerFormattersszámot.builder.Services.AddControllers() .AddXmlSerializerFormatters();Alkalmazza a
Consumesattribútumot olyan vezérlőosztályokra vagy műveleti módszerekre, amelyeknek XML-t kell várniuk a kérelem törzsében.[HttpPost] [Consumes("application/xml")] public ActionResult<Pet> Create(Pet pet)További információ: XML-szerializálás bemutatása.
Modellkötés testreszabása bemeneti formázókkal
A bemeneti formázó teljes felelősséget vállal azért, hogy adatokat olvas be a kérelem törzséből. A folyamat testreszabásához konfigurálja a bemeneti formázó által használt API-kat. Ez a szakasz azt ismerteti, hogyan szabhatja testre a System.Text.Json-alapú bemeneti formátumot a ObjectIdnevű egyéni típus megértéséhez.
Vegye figyelembe a következő modellt, amely egy egyéni ObjectId tulajdonságot tartalmaz:
public class InstructorObjectId
{
[Required]
public ObjectId ObjectId { get; set; } = null!;
}
Ha testreszabni szeretné a modellkötési folyamatot System.Text.Jsonhasználatakor, hozzon létre egy osztályt, amely származik 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);
}
Egyéni konverter használatához alkalmazza a JsonConverterAttribute attribútumot a típusra. Az alábbi példában a ObjectId típus egyéni konverterként ObjectIdConverter van konfigurálva:
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
További információért lásd: Hogyan írjunk egyéni konvertereket.
Megadott típusok kizárása a modellkötésből
A modellkötési és érvényesítési rendszerek viselkedését a ModelMetadatavezérli. Ön testre szabhatja a ModelMetadata egy részlet szolgáltató hozzáadásával az MvcOptions.ModelMetadataDetailsProviders-hez. A beépített részletek szolgáltatói a modellkötés letiltására vagy a megadott típusok érvényesítésére használhatók.
Ha le szeretné tiltani a modellkötést egy meghatározott típus összes modelljén, adjon hozzá egy ExcludeBindingMetadataProvider a Program.cs-ben. Ha például le szeretné tiltani a modellkötést az összes System.Versiontípusú modellen:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Ha le szeretné tiltani az ellenőrzést egy megadott típusú tulajdonságon, adjon hozzá egy SuppressChildValidationMetadataProvider a Program.cs-be. Például a System.Guidtípusú tulajdonságok érvényesítésének letiltásához:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Egyéni modellek összekötői
A modellkötés kibővítéséhez írjon egy egyéni modellkötőt, és a [ModelBinder] attribútummal válassza ki azt egy meghatározott célhoz. Tudjon meg többet az egyéni modellkötésről.
Manuális modellkötés
A modellkötés manuálisan hívható meg a TryUpdateModelAsync metódus használatával. A metódus ControllerBase és PageModel osztályokban is definiálva van. A metódustúlterhelésekkel lehetősége van megadni a használni kívánt előtagot és értékszolgáltatót. A metódus false ad vissza, ha a modellkötés meghiúsul. Íme egy példa:
if (await TryUpdateModelAsync(
newInstructor,
"Instructor",
x => x.Name, x => x.HireDate!))
{
_instructorStore.Add(newInstructor);
return RedirectToPage("./Index");
}
return Page();
TryUpdateModelAsync értékszolgáltatókat használ az űrlap törzséből, a lekérdezési sztringből és az útvonaladatok lekéréséhez.
TryUpdateModelAsync általában a következő:
- A Razor Lapok és MVC-alkalmazásokhoz használható vezérlőkkel és nézetekkel, hogy megakadályozza a túlzott közzétételt.
- Egy webes API-val nem használható, kivéve ha űrlapadatokból, lekérdezési karakterláncokból vagy útvonaladatokból történik a felhasználás. A JSON-t használó webes API-végpontok bemeneti formázókkal deszerializálják a kérelem törzsét egy objektumba.
További információért lásd TryUpdateModelAsync.
[FromServices] attribútum
Az attribútum neve az adatforrást meghatározó modellkötési attribútumok mintáját követi. De nem az értékszolgáltatótól származó adatok kötéséről van szó. Egy típuspéldányt kap a függőséginjektálási tárolóból. Célja, hogy alternatívát biztosítson a konstruktorinjektáláshoz, ha csak egy adott módszer meghívása esetén van szüksége szolgáltatásra.
Ha egy ilyen típusú példány nincs regisztrálva a függőséginjektálási tárolóban, az alkalmazás kivételt jelez a paraméter kötésekor. A paraméter opcionálissá tétele érdekében használja az alábbi módszerek egyikét:
- A paraméter null értékűvé tétele.
- Állítson be egy alapértelmezett értéket a paraméterhez.
Null értékű paraméterek esetén győződjön meg arról, hogy a paraméter nem null a hozzáférés előtt.
Json+PipeReader deszerializálás MVC-ben
A .NET 10-től kezdve a ASP.NET Core alábbi funkcionális területei a Stream helyett a PipeReader-alapú túlterheléseket használják JsonSerializer.DeserializeAsync :
- Minimális API-k (paraméterkötés, olvasási kérelem törzse)
- MVC (bemeneti formázók, modell)
- A HttpRequestJsonExtensions kérelem törzsének JSON-ként való olvasására használható bővítménymetelyek.
A legtöbb alkalmazás esetében a Streamről a PipeReaderre való áttérés jobb teljesítményt biztosít anélkül, hogy módosításokat kellene végrehajtania az alkalmazáskódban. Ha azonban az alkalmazás egyéni konverterrel rendelkezik, előfordulhat, hogy a konverter nem megfelelően működik Utf8JsonReader.HasValueSequence . Ha nem, az eredmény lehet például hiba, mint ArgumentOutOfRangeException vagy hiányzó adatok deszerializáláskor. A konverter pipeReaderrel kapcsolatos hibák nélkül történő működéséhez az alábbi lehetőségek állnak rendelkezésre.
1. lehetőség: Ideiglenes kerülő megoldás
A gyors áthidaló megoldás az, hogy visszatér a Streamhez a PipeReader támogatása nélkül. A beállítás implementálásához állítsa a "Microsoft.AspNetCore.UseStreamBasedJsonParsing" AppContext kapcsolót "true" értékre. Javasoljuk, hogy ezt csak ideiglenes kerülő megoldásként végezze el, és frissítse a konvertert, hogy a lehető leghamarabb támogatást nyújtson HasValueSequence . Előfordulhat, hogy a kapcsoló el lesz távolítva a .NET 11-ben. Az egyetlen célja az volt, hogy időt adjon a fejlesztőknek a konverterek frissítésére.
2. lehetőség: Az implementációk JsonConverter gyors javítása
Ehhez a javításhoz egy tömböt foglal le a ReadOnlySequence. Ez a példa a kód megjelenését mutatja be:
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan;
// previous code
}
3. lehetőség: Bonyolultabb, de jobb teljesítményű javítás
Ez a javítás magában foglalja egy külön kódútvonal beállítását a ReadOnlySequence kezeléshez:
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.HasValueSequence)
{
reader.ValueSequence;
// ReadOnlySequence optimized path
}
else
{
reader.ValueSpan;
// ReadOnlySpan optimized path
}
}
További információkért lásd:
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Modell-ellenőrzés az ASP.NET Core MVC-ben
- Egyéni modell kötése ASP.NET Core
Ez a cikk bemutatja, hogy mi a modellkötés, hogyan működik, és hogyan szabhatja testre a viselkedését.
Mi az a modellkötés?
A vezérlők és Razor lapok HTTP-kérelmekből származó adatokkal dolgoznak. Az útvonaladatok például megadhatnak egy rekordkulcsot, a közzétett űrlapmezők pedig értékeket adhatnak a modell tulajdonságaihoz. A kód megírása ezeknek az értékeknek a lekéréséhez és a sztringekből .NET-típusokká való konvertálásához fárasztó és hibalehetőségekkel járna. A modellkötés automatizálja ezt a folyamatot. A modellkötési rendszer:
- Adatokat kér le különböző forrásokból, például útvonaladatokból, űrlapmezőkből és lekérdezési sztringekből.
- Az adatokat a vezérlőknek és Razor oldalaknak biztosítja a metódusparaméterek és a nyilvános tulajdonságok útján.
- A sztringadatokat .NET-típusokká alakítja.
- Frissíti az összetett típusok tulajdonságait.
Example
Tegyük fel, hogy a következő műveleti módszerrel rendelkezik:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Az alkalmazás a következő URL-címmel kap egy kérést:
https://contoso.com/api/pets/2?DogsOnly=true
A modellkötés a következő lépéseken megy keresztül, miután az útválasztási rendszer kiválasztotta a műveletmetódust:
- Megkeresi a
GetByIdelső paraméterét , amely egyidnevű egész szám. - Megvizsgálja a HTTP-kérelemben elérhető forrásokat, és megkeresi a
id= "2" értéket az útvonaladatokban. - A "2" sztringet 2 egész számmá alakítja.
- Megkeresi a
GetByIdkövetkező paraméterét , egydogsOnlynevű logikai értéket. - Megvizsgálja a forrásokat, és megkeresi a "DogsOnly=true" kifejezést a lekérdezési sztringben. A névegyeztetés nem érzékeny a kis- és nagybetűkre.
- Az "true" sztringet booleán típusú
trueértékké alakítja át.
A keretrendszer ezután meghívja a GetById metódust, és a 2-t adja át a id paraméternek, valamint true-t adja át a dogsOnly paraméternek.
Az előző példában a modellkötési célok olyan metódusparaméterek, melyek egyszerű típusok. A célok egy összetett típus tulajdonságai is lehetnek. Az egyes tulajdonságok sikeres kötése után modellérvényesítési történik az adott tulajdonsághoz. A modellhez kötött adatok nyilvántartása, valamint bármely kötési vagy érvényesítési hiba a ControllerBase.ModelState vagy PageModel.ModelStatetárolva van. Annak kiderítéséhez, hogy a folyamat sikeres volt-e, az alkalmazás ellenőrzi a ModelState.IsValid jelzőt.
Targets
A modellkötés a következő típusú célok értékeit próbálja megtalálni:
- Annak a vezérlőműveleti metódusnak a paraméterei, amelyekre a kérések irányítva lesznek.
- Azon Razor Pages-kezelő metódus paraméterei, amelyekhez a kérések irányítva lesznek.
- Egy vezérlő vagy
PageModelosztály nyilvános tulajdonságai, ha az attribútumok meg vannak adva.
[BindProperty] attribútum
Egy vezérlő vagy PageModel osztály nyilvános tulajdonságára alkalmazható, hogy a modellkötés a tulajdonságot célozza:
public class EditModel : PageModel
{
[BindProperty]
public Instructor? Instructor { get; set; }
// ...
}
[BindProperties] attribútum
Egy vezérlőre vagy PageModel osztályra alkalmazható, hogy a modellkötés az osztály összes nyilvános tulajdonságát megcélzhassa:
[BindProperties]
public class CreateModel : PageModel
{
public Instructor? Instructor { get; set; }
// ...
}
Modellkötés HTTP GET-kérelmekhez
Alapértelmezés szerint a http GET-kérések nem kötik a tulajdonságokat. A GET-kéréshez általában csak egy rekordazonosító paraméter szükséges. A rekordazonosítóval megkereshető az elem az adatbázisban. Ezért nincs szükség olyan tulajdonság kötésére, amely a modell egy példányát tartalmazza. Olyan esetekben, amikor a GET-kérelmekből származó adatokhoz kötött tulajdonságokat szeretne, állítsa a SupportsGet tulajdonságot true:
[BindProperty(Name = "ai_user", SupportsGet = true)]
public string? ApplicationInsightsCookie { get; set; }
Egyszerű és összetett modellkötési típusok
A modellkötés meghatározott definíciókat használ az általa használt típusokhoz. A egyszerű típus egyetlen sztringből konvertálódik TypeConverter vagy TryParse metódus használatával. A összetett típus több bemeneti értékből konvertálódik. A keretrendszer egy TypeConverter vagy TryParsemegléte alapján határozza meg a különbséget . Javasoljuk, hogy hozzon létre egy típuskonvertert, vagy használjon TryParse egy stringSomeType átalakításhoz, amely nem igényel külső erőforrásokat vagy több bemenetet.
Sources
A modellkötés alapértelmezés szerint kulcs-érték párok formájában kéri le az adatokat egy HTTP-kérelem következő forrásaiból:
- Űrlapmezők
- A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
- Útvonal adatok
- Lekérdezési sztringparaméterek
- Feltöltött fájlok
Minden célparaméter vagy tulajdonság esetében a forrásokat az előző listában megadott sorrendben ellenőrzi a rendszer. Van néhány kivétel:
- Az útvonaladatok és a lekérdezési sztringértékek csak egyszerű típusokhoz használhatók.
- A feltöltött fájlok csak olyan céltípusokhoz vannak kötve, amelyek
IFormFilevagyIEnumerable<IFormFile>implementálnak.
Ha az alapértelmezett forrás helytelen, használja az alábbi attribútumok egyikét a forrás megadásához:
-
[FromQuery]– Lekéri a lekérdezési sztring értékeit. -
[FromRoute]– Lekéri az útvonaladatok értékeit. -
[FromForm]– Lekéri a beküldött űrlapmezők értékeit. -
[FromBody]– Lekéri az értékeket a kérelem törzséből. -
[FromHeader]– HTTP-fejlécekből származó értékeket kap.
Ezek az attribútumok:
A modelltulajdonságok egyenként vannak hozzáadva a modellosztályhoz, nem pedig a modellosztályhoz, ahogyan az alábbi példában látható:
public class Instructor { public int Id { get; set; } [FromQuery(Name = "Note")] public string? NoteFromQueryString { get; set; } // ... }Igény szerint elfogadhat egy modellnévértéket a konstruktorban. Ez a beállítás abban az esetben van megadva, ha a tulajdonság neve nem egyezik meg a kérelemben szereplő értékkel. A kérés értéke lehet például egy fejléc, amelynek nevében egy kötőjel szerepel, ahogyan az alábbi példában is látható:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] attribútum
Alkalmazza a [FromBody] attribútumot egy paraméterre, hogy a tulajdonságait egy HTTP-kérés törzséből töltse ki. A ASP.NET Core futtatókörnyezet egy bemeneti formázónak delegálja a törzs olvasásának felelősségét. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
Ha [FromBody] komplex típusú paraméterre van alkalmazva, a rendszer figyelmen kívül hagyja a tulajdonságokra alkalmazott kötési forrásattribútumokat. Az alábbi Create művelet például azt határozza meg, hogy a pet paramétere ki legyen töltve a törzsből:
public ActionResult<Pet> Create([FromBody] Pet pet)
A Pet osztály azt határozza meg, hogy a Breed tulajdonsága egy lekérdezési sztringparaméterből legyen feltöltve:
public class Pet
{
public string Name { get; set; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
Az előző példában:
- A
[FromQuery]attribútum figyelmen kívül lesz hagyva. - A
Breedtulajdonság nincs kitöltve lekérdezési sztringparaméterből.
A bemeneti formázók csak a törzset olvassák, és nem értik a kötés forrásattribútumait. Ha a törzsben talál egy megfelelő értéket, a rendszer ezt az értéket használja a Breed tulajdonság feltöltéséhez.
Ne alkalmazza a [FromBody] műveletmetódusonként egynél több paraméterre. Miután a kérelemfolyamot beolvassa egy bemeneti formázó, már nem olvasható újra más [FromBody] paraméterek kötéséhez.
További források
A forrásadatokat értékszolgáltatókadják meg a modellkötési rendszernek. Írhat és regisztrálhat olyan egyéni értékszolgáltatókat, amelyek más forrásokból származó modellkötési adatokat kérnek le. Előfordulhat például, hogy cookie-kból vagy munkamenet-állapotból szeretne adatokat. Adatok lekérése új forrásból:
- Hozzon létre egy
IValueProvidermegvalósító osztályt. - Hozzon létre egy
IValueProviderFactorymegvalósító osztályt. - Regisztrálja a gyári osztályt a
Program.cs-ban.
A minta egy értéket szolgáltató és egy generátor példát tartalmaz, amely a cookie-kból kap értékeket. A Program.csegyéni értékszolgáltató gyárainak regisztrálása:
builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});
Az előző kód az egyéni értékszolgáltatót az összes beépített értékszolgáltató után helyezi el. Ahhoz, hogy ez legyen az első a listában, Insert(0, new CookieValueProviderFactory())helyett hívja meg Add.
Nincs forrás egy modelltulajdonsághoz
Alapértelmezés szerint nem jön létre modellállapot-hiba, ha nem található érték egy modelltulajdonsághoz. A tulajdonság értéke null vagy alapértelmezett érték:
- A null értékű egyszerű típusok
nullértékre vannak állítva. - A nem null értékű értéktípusok értéke be van állítva
default(T). Egyint idparaméter például 0 értékre van állítva. - Összetett típusok esetén a modellkötés az alapértelmezett konstruktor használatával hoz létre egy példányt tulajdonságok megadása nélkül.
- A tömbök
Array.Empty<T>()értékre vannak beállítva, kivéve, hogy abyte[]tömböknullértékre vannak beállítva.
Ha a modell állapotát érvényteleníteni kell, ha nem található semmi a modelltulajdonság űrlapmezőiben, használja a [BindRequired] attribútumot.
Vegye figyelembe, hogy ez a [BindRequired] viselkedés a közzétett űrlapadatokból származó modellkötésekre vonatkozik, nem pedig a kérelem törzsében lévő JSON- vagy XML-adatokra. Az igénylés törzsadatait a bemeneti formázókkezelik.
Típuskonvertálási hibák
Ha talál egy forrást, de nem konvertálható céltípussá, a modell állapota érvénytelenként van megjelölve. A célparaméter vagy tulajdonság null értékűre vagy alapértelmezett értékre van állítva az előző szakaszban leírtak szerint.
A [ApiController] attribútummal rendelkező API-vezérlőben az érvénytelen modellállapot automatikus HTTP 400-választ eredményez.
Razor lapon jelenítse meg újra a lapot egy hibaüzenettel:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
Ha az előző kód visszajelzi a lapot, az érvénytelen bemenet nem jelenik meg az űrlapmezőben. Ennek az az oka, hogy a modelltulajdonság null értékűre vagy alapértelmezett értékre lett beállítva. Az érvénytelen bemenet megjelenik egy hibaüzenetben. Ha újra meg szeretné jeleníteni a hibás adatokat az űrlapmezőben, fontolja meg, hogy a modell tulajdonságát sztringként használja, és az adatkonvertálást manuálisan végezze el.
Ugyanez a stratégia akkor ajánlott, ha nem szeretné, hogy a típuskonvertálási hibák modellállapot-hibákat eredményeznek. Ebben az esetben változtassa a modell tulajdonságát stringgé.
Egyszerű típusok
Az egyszerű és összetett típusok magyarázatáért lásd a modellkötési és fejezeteket.
A modellkötő által forrássztringekké átalakítható egyszerű típusok a következők:
- Boolean
- Bájt, SByte
- Char
- DateOnly
- DateTime
- DateTimeOffset
- Decimal
- Double
- Enum
- Guid
- Int16, Int32, Int64
- Single
- TimeOnly
- TimeSpan
- UInt16, UInt32, UInt64
- Uri
- Version
Kötés a IParsable<T>.TryParse
A IParsable<TSelf>.TryParse API támogatja a kötésvezérlő műveleti paramétereinek értékeit:
public static bool TryParse (string? s, IFormatProvider? provider, out TSelf result);
Az alábbi DateRange osztály implementálja a IParsable<TSelf> a dátumtartomány kötésének támogatásához:
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;
}
}
Az előző kód:
- Két dátumot ábrázoló sztringet konvertál
DateRangeobjektummá - A modellkötő a
IParsable<TSelf>.TryParsemetódust használja aDateRangekötéséhez.
A következő vezérlőművelet a DateRange osztályt használja egy dátumtartomány kötéséhez:
// 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);
}
Az alábbi Locale osztály IParsable<TSelf> valósít meg a CultureInfokötésének támogatásához:
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;
}
}
}
A következő vezérlőművelet a Locale osztályt használja egy CultureInfo sztring kötéséhez:
// 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);
}
Az alábbi vezérlőművelet a DateRange és Locale osztályokkal köti össze a dátumtartományt 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);
}
A API-mintaalkalmazás a GitHubon egy korábbi példát jelenít meg egy API-vezérlőhöz.
Kötés a TryParse
A TryParse API támogatja a kötésvezérlő műveleti paramétereinek értékeit:
public static bool TryParse(string value, T out result);
public static bool TryParse(string value, IFormatProvider provider, T out result);
IParsable<T>.TryParse a paraméterkötés ajánlott megközelítése, mert a TryParseellentétben ez nem függ a tükröződéstől.
Az alábbi DateRangeTP osztály implementálja a 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;
}
}
A következő vezérlőművelet a DateRangeTP osztályt használja egy dátumtartomány kötéséhez:
// 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);
}
Összetett típusok
Egy összetett típusnak nyilvános alapértelmezett konstruktorsal és nyilvános írható tulajdonságokkal kell rendelkeznie a kötéshez. Modellkötés esetén az osztály példányosítása a nyilvános alapértelmezett konstruktor használatával történik.
Az összetett típus minden tulajdonsága esetében a modell kötés átnézi a forrásokat aprefix.property_namenévminta szerint. Ha semmi sem található, csak property_name keres az előtag nélkül. Az előtag használatára vonatkozó döntés nem tulajdonságonként történik. Ha például egy ?Instructor.Id=100&Name=footartalmazó lekérdezés OnGet(Instructor instructor)metódushoz van kötve, az eredményként kapott Instructor típusú objektum a következőket tartalmazza:
-
Id100értékre van állítva. -
Namenullértékre van állítva. A modellkötésInstructor.Namevár, mert az előző lekérdezési paraméterbenInstructor.Idhasználták.
Note
A .NET referenciaforrásra mutató dokumentációs hivatkozások általában betöltik az adattár alapértelmezett ágát, amely a .NET következő kiadásának aktuális fejlesztését jelöli. Egy adott kiadás címkéjének kiválasztásához használja az Ágak vagy címkék közötti váltás legördülő listát. További információ: A ASP.NET Core-forráskód (dotnet/AspNetCore.Docs #26205) verziócímkéjének kiválasztása.
A paraméterhez való kötésnél az előtag a paraméter neve. Egy PageModel nevű nyilvános tulajdonsághoz való kötés esetén az előtag a tulajdonság neve. Egyes attribútumok Prefix tulajdonságot használnak, amelyekkel felülbírálhatja a paraméter vagy a tulajdonságnév alapértelmezett használatát.
Tegyük fel például, hogy az összetett típus a következő Instructor osztály:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Előtag = paraméternév
Ha a kötendő modell egy instructorToUpdatenevű paraméter:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
A modellkötés a kulcs instructorToUpdate.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Előtag = tulajdonságnév
Ha a kötendő modell a vezérlő Instructor nevű tulajdonsága vagy a PageModel osztály:
[BindProperty]
public Instructor Instructor { get; set; }
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Egyéni előtag
Ha a kötendő modell egy instructorToUpdate nevű paraméter, és egy Bind attribútum Instructor határoz meg előtagként:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Attribútumok összetett típusú célokhoz
Összetett típusok modellkötésének szabályozásához számos beépített attribútum érhető el:
Warning
Ezek az attribútumok hatással vannak a modellkötésre, ha a közzétett űrlapadatok az értékek forrása. Nincsenek hatással a bemeneti formázók működésére, melyek feldolgozzák a közzétett JSON- és XML-kérelemtörzseket. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
[Kötés] attribútum
Alkalmazható osztályra vagy metódusparaméterre. Meghatározza, hogy a modell mely tulajdonságait kell szerepeltetni a modellkötésben.
[Bind] nem hatással a bemeneti formázókra.
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve, amikor bármely kezelőt vagy műveletmetódust meghívnak:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve a OnPost metódus meghívásakor:
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
A [Bind] attribútum használható a forgatókönyvek létrehozásakor a túlzott adatküldés elleni védelemre. Szerkesztési forgatókönyvekben nem működik jól, mert a kizárt tulajdonságok értéke null vagy alapértelmezett érték, ahelyett, hogy változatlan marad. A túlpostolás elleni védelem érdekében a [Bind] attribútum helyett a nézetmodellek használata ajánlott. További információ: biztonsági megjegyzés atúlpostolásáról.
[ModelBinder] attribútum
ModelBinderAttribute alkalmazhatók típusokra, tulajdonságokra vagy paraméterekre. Lehetővé teszi az adott példány vagy típus kötéséhez használt modellkötő típusának megadását. Például:
[HttpPost]
public IActionResult OnPost(
[ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)
A [ModelBinder] attribútum egy tulajdonság vagy paraméter nevének módosítására is használható modellkötés esetén:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
// ...
}
[BindRequired] attribútum
Ha a modell tulajdonságához nem lehetséges a kötés, a modellkötés modellállapot-hibát ad hozzá. Íme egy példa:
public class InstructorBindRequired
{
// ...
[BindRequired]
public DateTime HireDate { get; set; }
}
Lásd még a [Required] attribútumának ismertetését.
[BindNever] attribútum
Alkalmazható tulajdonságra vagy típusra. Megakadályozza azt, hogy a modell kötési folyamata beállítsa a modell tulajdonságát. Típusra alkalmazva a modellkötési rendszer kizárja a típus által definiált összes tulajdonságot. Íme egy példa:
public class InstructorBindNever
{
[BindNever]
public int Id { get; set; }
// ...
}
Collections
Az egyszerű típusok gyűjteményét tartalmazó célok esetében a modellkötés a parameter_name vagy property_nameegyezéseket keres. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a kötendő paraméter egy
selectedCoursesnevű tömb:public IActionResult OnPost(int? id, int[] selectedCourses)Az űrlap- vagy lekérdezési sztringadatok az alábbi formátumok egyikében lehetnek:
selectedCourses=1050&selectedCourses=2000selectedCourses[0]=1050&selectedCourses[1]=2000[0]=1050&[1]=2000selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b[a]=1050&[b]=2000&index=a&index=bKerülje egy
indexvagyIndexnevű paraméter vagy tulajdonság kötését, ha az egy gyűjteményérték mellett található. A modellkötés megpróbálja aindex-t gyűjteményindexként használni, ami helytelen kötéshez vezethet. Vegyük például a következő műveletet:public IActionResult Post(string index, List<Product> products)Az előző kódban a
indexlekérdezési sztring paraméter aindexmetódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi aindexparamétert, vagy modellkötési attribútumot használ a kötés konfigurálásához, elkerüli ezt a problémát:public IActionResult Post(string productIndex, List<Product> products)A következő formátum csak űrlapadatokban támogatott:
selectedCourses[]=1050&selectedCourses[]=2000Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a
selectedCoursesparaméternek:- selectedCourses[0]=1050
- selectedCourses[1]=2000
Alsó indexszámokat használó adatformátumoknak (... [0] ... [1] ...) meg kell győződniük arról, hogy nullától kezdve egymás után vannak számozva. Ha van rés az alsó indexszámozásban, a rendszer figyelmen kívül hagyja a rést követő összes elemet. Ha például az alsó indexek 0 és 1 helyett 0 és 2, akkor a második elemet figyelmen kívül hagyják.
Dictionaries
A Dictionary-célok esetében a modellkötés a parameter_name vagy property_nametalálatokat keresi. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a célparaméter egy
Dictionary<int, string>nevűselectedCourses:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)A közzétett űrlap- vagy lekérdezési sztringadatok az alábbi példák egyikéhez hasonlóan nézhetnek ki:
selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics[1050]=Chemistry&selectedCourses[2000]=EconomicsselectedCourses[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=EconomicsAz összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a
selectedCoursesparaméternek:- selectedCourses["1050"]="Chemistry"
- selectedCourses["2000"]="Economics"
Konstruktorkötés és rekordtípusok
A modellkötéshez az összetett típusok paraméter nélküli konstruktort igényelnek. Mind System.Text.Json, mind Newtonsoft.Json alapú bemeneti formázók támogatják a paraméter nélküli konstruktor nélküli osztályok deszerializálását.
A rekordtípusok kiválóan alkalmasak arra, hogy tömören ábrázolják az adatokat a hálózaton. ASP.NET Core egyetlen konstruktor használatával támogatja a modellkötést és a rekordtípusok érvényesítését:
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>
Rekordtípusok ellenőrzésekor a futtatókörnyezet a tulajdonságok helyett a paramétereken keres kötési és érvényesítési metaadatokat.
A keretrendszer lehetővé teszi a rekordtípusok kötését és érvényesítését:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Az előző működéshez a típusnak a következőnek kell lennie:
- Legyen rekordtípus.
- Pontosan egy nyilvános konstruktor.
- Olyan paramétereket tartalmaz, amelyek azonos nevű és típusú tulajdonsággal rendelkeznek. A nevek kis- és nagybetűk szerint nem különbözhetnek.
Paraméter nélküli konstruktorok nélküli POCO-k
Azok a POCO-k, amelyek nem rendelkeznek paraméter nélküli konstruktorokkal, nem köthetők.
Az alábbi kód kivételt eredményez, amely szerint a típusnak paraméter nélküli konstruktort kell tartalmaznia:
public class Person(string Name)
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0);
}
Rekordtípusok manuálisan létrehozott konstruktorokkal
Az elsődleges konstruktorokhoz hasonló, manuálisan létrehozott konstruktorokkal rendelkező rekordtípusok működnek
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; }
}
Rekordtípusok, érvényesítési és kötési metaadatok
Rekordtípusok esetében a paraméterek érvényesítési és kötési metaadatait használja a rendszer. A tulajdonságok metaadatai figyelmen kívül lesznek hagyva
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; }
}
Érvényesítés és metaadatok
Az ellenőrzés metaadatokat használ a paraméteren, de a tulajdonság használatával olvassa be az értéket. Az elsődleges konstruktorok esetében a kettő azonos lenne. Vannak azonban módszerek a legyőzésére:
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; }
}
A TryUpdateModel nem frissíti a rekordtípus paramétereit
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
Ebben az esetben az MVC nem próbálja meg újra megkötni Name. A Age azonban frissíthető
Modellkötés útvonaladatainak és lekérdezési sztringjeinek globalizációs viselkedése
A ASP.NET Fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató:
- Értékeket invariáns kultúraként kezelni.
- Arra számít, hogy az URL-címek kulturális invariánsak.
Ezzel szemben az űrlapadatokból származó értékek kultúraérzékeny átalakításon mennek keresztül. Az URL-címek szándékosan úgy vannak kialakítva, hogy megoszthatóak legyenek az egyes területek között.
A ASP.NET fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató kulturális szempontból érzékeny átalakításon megy keresztül:
- Származzon a IValueProviderFactory-ból
- Másolja az alábbi kódot QueryStringValueProviderFactory vagy RouteValueValueProviderFactory
- Cserélje le az értékszolgáltató konstruktorának átadott kulturálisCultureInfo.CurrentCulture
- Cserélje le az alapértelmezett értékszolgáltató gyárat az MVC-beállításokban az Ön új értékszolgáltatójára.
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ális adattípusok
Vannak speciális adattípusok, amelyeket a modellkötés képes kezelni.
IFormFile és IFormFileCollection
A HTTP-kérelemben szereplő feltöltött fájl. Támogatott a IEnumerable<IFormFile> több fájlhoz is.
CancellationToken
A műveletek opcionálisan paraméterként köthetnek egy CancellationToken. Ez köti RequestAborted, amely jelzi, ha a HTTP-kérés alapjául szolgáló kapcsolat megszakad. A műveletek ezzel a paraméterrel megszakíthatják a vezérlőműveletek részeként végrehajtott hosszú ideig futó aszinkron műveleteket.
FormCollection
Az összes érték lekérésére szolgál a közzétett űrlapadatokból.
Bemeneti formázók
A kérelem törzsében lévő adatok lehetnek JSON-, XML- vagy egyéb formátumúak. Az adatok elemzéséhez a modellkötés egy bemeneti formázó használ, amely egy adott tartalomtípus kezelésére van konfigurálva. Alapértelmezés szerint a ASP.NET Core JSON-alapú bemeneti formázókat tartalmaz a JSON-adatok kezeléséhez. Más tartalomtípusokhoz más formátumkészítőket is hozzáadhat.
ASP.NET Core a attribútum alapján választja ki a bemeneti formázókat. Ha nincs attribútum, akkor a Content-Type fejlécet használja.
A beépített XML-bemeneti formázók használata:
Hívja a
Program.cs, AddXmlSerializerFormatters vagy AddXmlDataContractSerializerFormattersszámot.builder.Services.AddControllers() .AddXmlSerializerFormatters();Alkalmazza a
Consumesattribútumot olyan vezérlőosztályokra vagy műveleti módszerekre, amelyeknek XML-t kell várniuk a kérelem törzsében.[HttpPost] [Consumes("application/xml")] public ActionResult<Pet> Create(Pet pet)További információ: XML-szerializálás bemutatása.
Modellkötés testreszabása bemeneti formázókkal
A bemeneti formázó teljes felelősséget vállal azért, hogy adatokat olvas be a kérelem törzséből. A folyamat testreszabásához konfigurálja a bemeneti formázó által használt API-kat. Ez a szakasz azt ismerteti, hogyan szabhatja testre a System.Text.Json-alapú bemeneti formátumot a ObjectIdnevű egyéni típus megértéséhez.
Vegye figyelembe a következő modellt, amely egy egyéni ObjectId tulajdonságot tartalmaz:
public class InstructorObjectId
{
[Required]
public ObjectId ObjectId { get; set; } = null!;
}
Ha testreszabni szeretné a modellkötési folyamatot System.Text.Jsonhasználatakor, hozzon létre egy osztályt, amely származik 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);
}
Egyéni konverter használatához alkalmazza a JsonConverterAttribute attribútumot a típusra. Az alábbi példában a ObjectId típus egyéni konverterként ObjectIdConverter van konfigurálva:
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
További információért lásd: Hogyan írjunk egyéni konvertereket.
Megadott típusok kizárása a modellkötésből
A modellkötési és érvényesítési rendszerek viselkedését a ModelMetadatavezérli. Ön testre szabhatja a ModelMetadata egy részlet szolgáltató hozzáadásával az MvcOptions.ModelMetadataDetailsProviders-hez. A beépített részletek szolgáltatói a modellkötés letiltására vagy a megadott típusok érvényesítésére használhatók.
Ha le szeretné tiltani a modellkötést egy meghatározott típus összes modelljén, adjon hozzá egy ExcludeBindingMetadataProvider a Program.cs-ben. Ha például le szeretné tiltani a modellkötést az összes System.Versiontípusú modellen:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Ha le szeretné tiltani az ellenőrzést egy megadott típusú tulajdonságon, adjon hozzá egy SuppressChildValidationMetadataProvider a Program.cs-be. Például a System.Guidtípusú tulajdonságok érvényesítésének letiltásához:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Egyéni modellek összekötői
A modellkötés kibővítéséhez írjon egy egyéni modellkötőt, és a [ModelBinder] attribútummal válassza ki azt egy meghatározott célhoz. Tudjon meg többet az egyéni modellkötésről.
Manuális modellkötés
A modellkötés manuálisan hívható meg a TryUpdateModelAsync metódus használatával. A metódus ControllerBase és PageModel osztályokban is definiálva van. A metódustúlterhelésekkel lehetősége van megadni a használni kívánt előtagot és értékszolgáltatót. A metódus false ad vissza, ha a modellkötés meghiúsul. Íme egy példa:
if (await TryUpdateModelAsync(
newInstructor,
"Instructor",
x => x.Name, x => x.HireDate!))
{
_instructorStore.Add(newInstructor);
return RedirectToPage("./Index");
}
return Page();
TryUpdateModelAsync értékszolgáltatókat használ az űrlap törzséből, a lekérdezési sztringből és az útvonaladatok lekéréséhez.
TryUpdateModelAsync általában a következő:
- A Razor Lapok és MVC-alkalmazásokhoz használható vezérlőkkel és nézetekkel, hogy megakadályozza a túlzott közzétételt.
- Egy webes API-val nem használható, kivéve ha űrlapadatokból, lekérdezési karakterláncokból vagy útvonaladatokból történik a felhasználás. A JSON-t használó webes API-végpontok bemeneti formázókkal deszerializálják a kérelem törzsét egy objektumba.
További információért lásd TryUpdateModelAsync.
[FromServices] attribútum
Az attribútum neve az adatforrást meghatározó modellkötési attribútumok mintáját követi. De nem az értékszolgáltatótól származó adatok kötéséről van szó. Egy típuspéldányt kap a függőséginjektálási tárolóból. Célja, hogy alternatívát biztosítson a konstruktorinjektáláshoz, ha csak egy adott módszer meghívása esetén van szüksége szolgáltatásra.
Ha egy ilyen típusú példány nincs regisztrálva a függőséginjektálási tárolóban, az alkalmazás kivételt jelez a paraméter kötésekor. A paraméter opcionálissá tétele érdekében használja az alábbi módszerek egyikét:
- A paraméter null értékűvé tétele.
- Állítson be egy alapértelmezett értéket a paraméterhez.
Null értékű paraméterek esetén győződjön meg arról, hogy a paraméter nem null a hozzáférés előtt.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Modell-ellenőrzés az ASP.NET Core MVC-ben
- Egyéni modell kötése ASP.NET Core
Ez a cikk bemutatja, hogy mi a modellkötés, hogyan működik, és hogyan szabhatja testre a viselkedését.
Mi az a modellkötés?
A vezérlők és Razor lapok HTTP-kérelmekből származó adatokkal dolgoznak. Az útvonaladatok például megadhatnak egy rekordkulcsot, a közzétett űrlapmezők pedig értékeket adhatnak a modell tulajdonságaihoz. A kód megírása ezeknek az értékeknek a lekéréséhez és a sztringekből .NET-típusokká való konvertálásához fárasztó és hibalehetőségekkel járna. A modellkötés automatizálja ezt a folyamatot. A modellkötési rendszer:
- Adatokat kér le különböző forrásokból, például útvonaladatokból, űrlapmezőkből és lekérdezési sztringekből.
- Az adatokat a vezérlőknek és Razor oldalaknak biztosítja a metódusparaméterek és a nyilvános tulajdonságok útján.
- A sztringadatokat .NET-típusokká alakítja.
- Frissíti az összetett típusok tulajdonságait.
Example
Tegyük fel, hogy a következő műveleti módszerrel rendelkezik:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Az alkalmazás a következő URL-címmel kap egy kérést:
https://contoso.com/api/pets/2?DogsOnly=true
A modellkötés a következő lépéseken megy keresztül, miután az útválasztási rendszer kiválasztotta a műveletmetódust:
- Megkeresi a
GetByIdelső paraméterét , amely egyidnevű egész szám. - Megvizsgálja a HTTP-kérelemben elérhető forrásokat, és megkeresi a
id= "2" értéket az útvonaladatokban. - A "2" sztringet 2 egész számmá alakítja.
- Megkeresi a
GetByIdkövetkező paraméterét , egydogsOnlynevű logikai értéket. - Megvizsgálja a forrásokat, és megkeresi a "DogsOnly=true" kifejezést a lekérdezési sztringben. A névegyeztetés nem érzékeny a kis- és nagybetűkre.
- Az "true" sztringet booleán típusú
trueértékké alakítja át.
A keretrendszer ezután meghívja a GetById metódust, és a 2-t adja át a id paraméternek, valamint true-t adja át a dogsOnly paraméternek.
Az előző példában a modellkötési célok egyszerű típusú metódusparaméterek. A célok egy összetett típus tulajdonságai is lehetnek. Az egyes tulajdonságok sikeres kötése után modellérvényesítési történik az adott tulajdonsághoz. A modellhez kötött adatok nyilvántartása, valamint bármely kötési vagy érvényesítési hiba a ControllerBase.ModelState vagy PageModel.ModelStatetárolva van. Annak kiderítéséhez, hogy a folyamat sikeres volt-e, az alkalmazás ellenőrzi a ModelState.IsValid jelzőt.
Targets
A modellkötés a következő típusú célok értékeit próbálja megtalálni:
- Annak a vezérlőműveleti metódusnak a paraméterei, amelyekre a kérések irányítva lesznek.
- Azon Razor Pages-kezelő metódus paraméterei, amelyekhez a kérések irányítva lesznek.
- Egy vezérlő vagy
PageModelosztály nyilvános tulajdonságai, ha az attribútumok meg vannak adva.
[BindProperty] attribútum
Egy vezérlő vagy PageModel osztály nyilvános tulajdonságára alkalmazható, hogy a modellkötés a tulajdonságot célozza:
public class EditModel : PageModel
{
[BindProperty]
public Instructor? Instructor { get; set; }
// ...
}
[BindProperties] attribútum
Egy vezérlőre vagy PageModel osztályra alkalmazható, hogy a modellkötés az osztály összes nyilvános tulajdonságát megcélzhassa:
[BindProperties]
public class CreateModel : PageModel
{
public Instructor? Instructor { get; set; }
// ...
}
Modellkötés HTTP GET-kérelmekhez
Alapértelmezés szerint a http GET-kérések nem kötik a tulajdonságokat. A GET-kéréshez általában csak egy rekordazonosító paraméter szükséges. A rekordazonosítóval megkereshető az elem az adatbázisban. Ezért nincs szükség olyan tulajdonság kötésére, amely a modell egy példányát tartalmazza. Olyan esetekben, amikor a GET-kérelmekből származó adatokhoz kötött tulajdonságokat szeretne, állítsa a SupportsGet tulajdonságot true:
[BindProperty(Name = "ai_user", SupportsGet = true)]
public string? ApplicationInsightsCookie { get; set; }
Sources
A modellkötés alapértelmezés szerint kulcs-érték párok formájában kéri le az adatokat egy HTTP-kérelem következő forrásaiból:
- Űrlapmezők
- A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
- Útvonal adatok
- Lekérdezési sztringparaméterek
- Feltöltött fájlok
Minden célparaméter vagy tulajdonság esetében a forrásokat az előző listában megadott sorrendben ellenőrzi a rendszer. Van néhány kivétel:
- Az útvonaladatok és a lekérdezési sztringértékek csak egyszerű típusok esetén használhatók.
- A feltöltött fájlok csak olyan céltípusokhoz vannak kötve, amelyek
IFormFilevagyIEnumerable<IFormFile>implementálnak.
Ha az alapértelmezett forrás helytelen, használja az alábbi attribútumok egyikét a forrás megadásához:
-
[FromQuery]– Lekéri a lekérdezési sztring értékeit. -
[FromRoute]– Lekéri az útvonaladatok értékeit. -
[FromForm]– Lekéri a beküldött űrlapmezők értékeit. -
[FromBody]– Lekéri az értékeket a kérelem törzséből. -
[FromHeader]– HTTP-fejlécekből származó értékeket kap.
Ezek az attribútumok:
A modelltulajdonságok egyenként vannak hozzáadva a modellosztályhoz, nem pedig a modellosztályhoz, ahogyan az alábbi példában látható:
public class Instructor { public int Id { get; set; } [FromQuery(Name = "Note")] public string? NoteFromQueryString { get; set; } // ... }Igény szerint elfogadhat egy modellnévértéket a konstruktorban. Ez a beállítás abban az esetben van megadva, ha a tulajdonság neve nem egyezik meg a kérelemben szereplő értékkel. A kérés értéke lehet például egy fejléc, amelynek nevében egy kötőjel szerepel, ahogyan az alábbi példában is látható:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] attribútum
Alkalmazza a [FromBody] attribútumot egy paraméterre, hogy a tulajdonságait egy HTTP-kérés törzséből töltse ki. A ASP.NET Core futtatókörnyezet egy bemeneti formázónak delegálja a törzs olvasásának felelősségét. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
Ha [FromBody] komplex típusú paraméterre van alkalmazva, a rendszer figyelmen kívül hagyja a tulajdonságokra alkalmazott kötési forrásattribútumokat. Az alábbi Create művelet például azt határozza meg, hogy a pet paramétere ki legyen töltve a törzsből:
public ActionResult<Pet> Create([FromBody] Pet pet)
A Pet osztály azt határozza meg, hogy a Breed tulajdonsága egy lekérdezési sztringparaméterből legyen feltöltve:
public class Pet
{
public string Name { get; set; } = null!;
[FromQuery] // Attribute is ignored.
public string Breed { get; set; } = null!;
}
Az előző példában:
- A
[FromQuery]attribútum figyelmen kívül lesz hagyva. - A
Breedtulajdonság nincs kitöltve lekérdezési sztringparaméterből.
A bemeneti formázók csak a törzset olvassák, és nem értik a kötés forrásattribútumait. Ha a törzsben talál egy megfelelő értéket, a rendszer ezt az értéket használja a Breed tulajdonság feltöltéséhez.
Ne alkalmazza a [FromBody] műveletmetódusonként egynél több paraméterre. Miután a kérelemfolyamot beolvassa egy bemeneti formázó, már nem olvasható újra más [FromBody] paraméterek kötéséhez.
További források
A forrásadatokat értékszolgáltatókadják meg a modellkötési rendszernek. Írhat és regisztrálhat olyan egyéni értékszolgáltatókat, amelyek más forrásokból származó modellkötési adatokat kérnek le. Előfordulhat például, hogy cookie-kból vagy munkamenet-állapotból szeretne adatokat. Adatok lekérése új forrásból:
- Hozzon létre egy
IValueProvidermegvalósító osztályt. - Hozzon létre egy
IValueProviderFactorymegvalósító osztályt. - Regisztrálja a gyári osztályt a
Program.cs-ban.
A minta egy értéket szolgáltató és egy generátor példát tartalmaz, amely a cookie-kból kap értékeket. A Program.csegyéni értékszolgáltató gyárainak regisztrálása:
builder.Services.AddControllers(options =>
{
options.ValueProviderFactories.Add(new CookieValueProviderFactory());
});
Az előző kód az egyéni értékszolgáltatót az összes beépített értékszolgáltató után helyezi el. Ahhoz, hogy ez legyen az első a listában, Insert(0, new CookieValueProviderFactory())helyett hívja meg Add.
Nincs forrás egy modelltulajdonsághoz
Alapértelmezés szerint nem jön létre modellállapot-hiba, ha nem található érték egy modelltulajdonsághoz. A tulajdonság értéke null vagy alapértelmezett érték:
- A null értéket is felvevő egyszerű típusok
null-re vannak állítva. - A nem null értékű értéktípusok értéke be van állítva
default(T). Egyint idparaméter például 0 értékre van állítva. - Összetett típusok esetén a modellkötés az alapértelmezett konstruktor használatával hoz létre egy példányt tulajdonságok megadása nélkül.
- A tömbök
Array.Empty<T>()értékre vannak beállítva, kivéve, hogy abyte[]tömböknullértékre vannak beállítva.
Ha a modell állapotát érvényteleníteni kell, ha nem található semmi a modelltulajdonság űrlapmezőiben, használja a [BindRequired] attribútumot.
Vegye figyelembe, hogy ez a [BindRequired] viselkedés a közzétett űrlapadatokból származó modellkötésekre vonatkozik, nem pedig a kérelem törzsében lévő JSON- vagy XML-adatokra. Az igénylés törzsadatait a bemeneti formázókkezelik.
Típuskonvertálási hibák
Ha talál egy forrást, de nem konvertálható céltípussá, a modell állapota érvénytelenként van megjelölve. A célparaméter vagy tulajdonság null értékűre vagy alapértelmezett értékre van állítva az előző szakaszban leírtak szerint.
A [ApiController] attribútummal rendelkező API-vezérlőben az érvénytelen modellállapot automatikus HTTP 400-választ eredményez.
Razor lapon jelenítse meg újra a lapot egy hibaüzenettel:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
// ...
return RedirectToPage("./Index");
}
Ha az előző kód visszajelzi a lapot, az érvénytelen bemenet nem jelenik meg az űrlapmezőben. Ennek az az oka, hogy a modelltulajdonság null értékűre vagy alapértelmezett értékre lett beállítva. Az érvénytelen bemenet megjelenik egy hibaüzenetben. Ha újra meg szeretné jeleníteni a hibás adatokat az űrlapmezőben, fontolja meg, hogy a modell tulajdonságát sztringként használja, és az adatkonvertálást manuálisan végezze el.
Ugyanez a stratégia akkor ajánlott, ha nem szeretné, hogy a típuskonvertálási hibák modellállapot-hibákat eredményeznek. Ebben az esetben változtassa a modell tulajdonságát stringgé.
Egyszerű típusok
A modellkötő által forrássztringekké átalakítható egyszerű típusok a következők:
- Boolean
- Bájt, SByte
- Char
- DateTime
- DateTimeOffset
- Decimal
- Double
- Enum
- Guid
- Int16, Int32, Int64
- Single
- TimeSpan
- UInt16, UInt32, UInt64
- Uri
- Version
Összetett típusok
Egy összetett típusnak nyilvános alapértelmezett konstruktorsal és nyilvános írható tulajdonságokkal kell rendelkeznie a kötéshez. Modellkötés esetén az osztály példányosítása a nyilvános alapértelmezett konstruktor használatával történik.
Az összetett típus minden tulajdonsága esetében a modell kötés átnézi a forrásokat aprefix.property_namenévminta szerint. Ha semmi sem található, csak property_name keres az előtag nélkül. Az előtag használatára vonatkozó döntés nem tulajdonságonként történik. Ha például egy ?Instructor.Id=100&Name=footartalmazó lekérdezés OnGet(Instructor instructor)metódushoz van kötve, az eredményként kapott Instructor típusú objektum a következőket tartalmazza:
-
Id100értékre van állítva. -
Namenullértékre van állítva. A modellkötésInstructor.Namevár, mert az előző lekérdezési paraméterbenInstructor.Idhasználták.
Note
A .NET referenciaforrásra mutató dokumentációs hivatkozások általában betöltik az adattár alapértelmezett ágát, amely a .NET következő kiadásának aktuális fejlesztését jelöli. Egy adott kiadás címkéjének kiválasztásához használja az Ágak vagy címkék közötti váltás legördülő listát. További információ: A ASP.NET Core-forráskód (dotnet/AspNetCore.Docs #26205) verziócímkéjének kiválasztása.
A paraméterhez való kötésnél az előtag a paraméter neve. Egy PageModel nevű nyilvános tulajdonsághoz való kötés esetén az előtag a tulajdonság neve. Egyes attribútumok Prefix tulajdonságot használnak, amelyekkel felülbírálhatja a paraméter vagy a tulajdonságnév alapértelmezett használatát.
Tegyük fel például, hogy az összetett típus a következő Instructor osztály:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Előtag = paraméternév
Ha a kötendő modell egy instructorToUpdatenevű paraméter:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
A modellkötés a kulcs instructorToUpdate.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Előtag = tulajdonságnév
Ha a kötendő modell a vezérlő Instructor nevű tulajdonsága vagy a PageModel osztály:
[BindProperty]
public Instructor Instructor { get; set; }
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Egyéni előtag
Ha a kötendő modell egy instructorToUpdate nevű paraméter, és egy Bind attribútum Instructor határoz meg előtagként:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Attribútumok összetett típusú célokhoz
Összetett típusok modellkötésének szabályozásához számos beépített attribútum érhető el:
Warning
Ezek az attribútumok hatással vannak a modellkötésre, ha a közzétett űrlapadatok az értékek forrása. Nincsenek hatással a bemeneti formázók működésére, melyek feldolgozzák a közzétett JSON- és XML-kérelemtörzseket. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
[Kötés] attribútum
Alkalmazható osztályra vagy metódusparaméterre. Meghatározza, hogy a modell mely tulajdonságait kell szerepeltetni a modellkötésben.
[Bind] nem hatással a bemeneti formázókra.
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve, amikor bármely kezelőt vagy műveletmetódust meghívnak:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve a OnPost metódus meghívásakor:
[HttpPost]
public IActionResult OnPost(
[Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
A [Bind] attribútum használható a forgatókönyvek létrehozásakor a túlzott adatküldés elleni védelemre. Szerkesztési forgatókönyvekben nem működik jól, mert a kizárt tulajdonságok értéke null vagy alapértelmezett érték, ahelyett, hogy változatlan marad. A túlpostolás elleni védelem érdekében a [Bind] attribútum helyett a nézetmodellek használata ajánlott. További információ: biztonsági megjegyzés atúlpostolásáról.
[ModelBinder] attribútum
ModelBinderAttribute alkalmazhatók típusokra, tulajdonságokra vagy paraméterekre. Lehetővé teszi az adott példány vagy típus kötéséhez használt modellkötő típusának megadását. Például:
[HttpPost]
public IActionResult OnPost(
[ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)
A [ModelBinder] attribútum egy tulajdonság vagy paraméter nevének módosítására is használható modellkötés esetén:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
// ...
}
[BindRequired] attribútum
Ha a modell tulajdonságához nem lehetséges a kötés, a modellkötés modellállapot-hibát ad hozzá. Íme egy példa:
public class InstructorBindRequired
{
// ...
[BindRequired]
public DateTime HireDate { get; set; }
}
Lásd még a [Required] attribútumának ismertetését.
[BindNever] attribútum
Alkalmazható tulajdonságra vagy típusra. Megakadályozza azt, hogy a modell kötési folyamata beállítsa a modell tulajdonságát. Típusra alkalmazva a modellkötési rendszer kizárja a típus által definiált összes tulajdonságot. Íme egy példa:
public class InstructorBindNever
{
[BindNever]
public int Id { get; set; }
// ...
}
Collections
Az egyszerű típusok gyűjteményét tartalmazó célok esetében a modellkötés a parameter_name vagy property_nameegyezéseket keres. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a kötendő paraméter egy
selectedCoursesnevű tömb:public IActionResult OnPost(int? id, int[] selectedCourses)Az űrlap- vagy lekérdezési sztringadatok az alábbi formátumok egyikében lehetnek:
selectedCourses=1050&selectedCourses=2000selectedCourses[0]=1050&selectedCourses[1]=2000[0]=1050&[1]=2000selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b[a]=1050&[b]=2000&index=a&index=bKerülje egy
indexvagyIndexnevű paraméter vagy tulajdonság kötését, ha az egy gyűjteményérték mellett található. A modellkötés megpróbálja aindex-t gyűjteményindexként használni, ami helytelen kötéshez vezethet. Vegyük például a következő műveletet:public IActionResult Post(string index, List<Product> products)Az előző kódban a
indexlekérdezési sztring paraméter aindexmetódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi aindexparamétert, vagy modellkötési attribútumot használ a kötés konfigurálásához, elkerüli ezt a problémát:public IActionResult Post(string productIndex, List<Product> products)A következő formátum csak űrlapadatokban támogatott:
selectedCourses[]=1050&selectedCourses[]=2000Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a
selectedCoursesparaméternek:- selectedCourses[0]=1050
- selectedCourses[1]=2000
Alsó indexszámokat használó adatformátumoknak (... [0] ... [1] ...) meg kell győződniük arról, hogy nullától kezdve egymás után vannak számozva. Ha van rés az alsó indexszámozásban, a rendszer figyelmen kívül hagyja a rést követő összes elemet. Ha például az alsó indexek 0 és 1 helyett 0 és 2, akkor a második elemet figyelmen kívül hagyják.
Dictionaries
A Dictionary-célok esetében a modellkötés a parameter_name vagy property_nametalálatokat keresi. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a célparaméter egy
Dictionary<int, string>nevűselectedCourses:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)A közzétett űrlap- vagy lekérdezési sztringadatok az alábbi példák egyikéhez hasonlóan nézhetnek ki:
selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics[1050]=Chemistry&selectedCourses[2000]=EconomicsselectedCourses[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=EconomicsAz összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a
selectedCoursesparaméternek:- selectedCourses["1050"]="Chemistry"
- selectedCourses["2000"]="Economics"
Konstruktorkötés és rekordtípusok
A modellkötéshez az összetett típusok paraméter nélküli konstruktort igényelnek. Mind System.Text.Json, mind Newtonsoft.Json alapú bemeneti formázók támogatják a paraméter nélküli konstruktor nélküli osztályok deszerializálását.
A rekordtípusok kiválóan alkalmasak arra, hogy tömören ábrázolják az adatokat a hálózaton. ASP.NET Core egyetlen konstruktor használatával támogatja a modellkötést és a rekordtípusok érvényesítését:
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>
Rekordtípusok ellenőrzésekor a futtatókörnyezet a tulajdonságok helyett a paramétereken keres kötési és érvényesítési metaadatokat.
A keretrendszer lehetővé teszi a rekordtípusok kötését és érvényesítését:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Az előző működéshez a típusnak a következőnek kell lennie:
- Legyen rekordtípus.
- Pontosan egy nyilvános konstruktor.
- Olyan paramétereket tartalmaz, amelyek azonos nevű és típusú tulajdonsággal rendelkeznek. A nevek kis- és nagybetűk szerint nem különbözhetnek.
Paraméter nélküli konstruktorok nélküli POCO-k
Azok a POCO-k, amelyek nem rendelkeznek paraméter nélküli konstruktorokkal, nem köthetők.
Az alábbi kód kivételt eredményez, amely szerint a típusnak paraméter nélküli konstruktort kell tartalmaznia:
public class Person(string Name)
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0);
}
Rekordtípusok manuálisan létrehozott konstruktorokkal
Az elsődleges konstruktorokhoz hasonló, manuálisan létrehozott konstruktorokkal rendelkező rekordtípusok működnek
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; }
}
Rekordtípusok, érvényesítési és kötési metaadatok
Rekordtípusok esetében a paraméterek érvényesítési és kötési metaadatait használja a rendszer. A tulajdonságok metaadatai figyelmen kívül lesznek hagyva
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; }
}
Érvényesítés és metaadatok
Az ellenőrzés metaadatokat használ a paraméteren, de a tulajdonság használatával olvassa be az értéket. Az elsődleges konstruktorok esetében a kettő azonos lenne. Vannak azonban módszerek a legyőzésére:
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; }
}
A TryUpdateModel nem frissíti a rekordtípus paramétereit
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
Ebben az esetben az MVC nem próbálja meg újra megkötni Name. A Age azonban frissíthető
Modellkötés útvonaladatainak és lekérdezési sztringjeinek globalizációs viselkedése
A ASP.NET Fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató:
- Értékeket invariáns kultúraként kezelni.
- Arra számít, hogy az URL-címek kulturális invariánsak.
Ezzel szemben az űrlapadatokból származó értékek kultúraérzékeny átalakításon mennek keresztül. Az URL-címek szándékosan úgy vannak kialakítva, hogy megoszthatóak legyenek az egyes területek között.
A ASP.NET fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató kulturális szempontból érzékeny átalakításon megy keresztül:
- Származzon a IValueProviderFactory-ból
- Másolja az alábbi kódot QueryStringValueProviderFactory vagy RouteValueValueProviderFactory
- Cserélje le az értékszolgáltató konstruktorának átadott kulturálisCultureInfo.CurrentCulture
- Cserélje le az alapértelmezett értékszolgáltató gyárat az MVC-beállításokban az Ön új értékszolgáltatójára.
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ális adattípusok
Vannak speciális adattípusok, amelyeket a modellkötés képes kezelni.
IFormFile és IFormFileCollection
A HTTP-kérelemben szereplő feltöltött fájl. Támogatott a IEnumerable<IFormFile> több fájlhoz is.
CancellationToken
A műveletek opcionálisan paraméterként köthetnek egy CancellationToken. Ez köti RequestAborted, amely jelzi, ha a HTTP-kérés alapjául szolgáló kapcsolat megszakad. A műveletek ezzel a paraméterrel megszakíthatják a vezérlőműveletek részeként végrehajtott hosszú ideig futó aszinkron műveleteket.
FormCollection
Az összes érték lekérésére szolgál a közzétett űrlapadatokból.
Bemeneti formázók
A kérelem törzsében lévő adatok lehetnek JSON-, XML- vagy egyéb formátumúak. Az adatok elemzéséhez a modellkötés egy bemeneti formázó használ, amely egy adott tartalomtípus kezelésére van konfigurálva. Alapértelmezés szerint a ASP.NET Core JSON-alapú bemeneti formázókat tartalmaz a JSON-adatok kezeléséhez. Más tartalomtípusokhoz más formátumkészítőket is hozzáadhat.
ASP.NET Core a attribútum alapján választja ki a bemeneti formázókat. Ha nincs attribútum, akkor a Content-Type fejlécet használja.
A beépített XML-bemeneti formázók használata:
Hívja a
Program.cs, AddXmlSerializerFormatters vagy AddXmlDataContractSerializerFormattersszámot.builder.Services.AddControllers() .AddXmlSerializerFormatters();Alkalmazza a
Consumesattribútumot olyan vezérlőosztályokra vagy műveleti módszerekre, amelyeknek XML-t kell várniuk a kérelem törzsében.[HttpPost] [Consumes("application/xml")] public ActionResult<Pet> Create(Pet pet)További információ: XML-szerializálás bemutatása.
Modellkötés testreszabása bemeneti formázókkal
A bemeneti formázó teljes felelősséget vállal azért, hogy adatokat olvas be a kérelem törzséből. A folyamat testreszabásához konfigurálja a bemeneti formázó által használt API-kat. Ez a szakasz azt ismerteti, hogyan szabhatja testre a System.Text.Json-alapú bemeneti formátumot a ObjectIdnevű egyéni típus megértéséhez.
Vegye figyelembe a következő modellt, amely egy egyéni ObjectId tulajdonságot tartalmaz:
public class InstructorObjectId
{
[Required]
public ObjectId ObjectId { get; set; } = null!;
}
Ha testreszabni szeretné a modellkötési folyamatot System.Text.Jsonhasználatakor, hozzon létre egy osztályt, amely származik 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);
}
Egyéni konverter használatához alkalmazza a JsonConverterAttribute attribútumot a típusra. Az alábbi példában a ObjectId típus egyéni konverterként ObjectIdConverter van konfigurálva:
[JsonConverter(typeof(ObjectIdConverter))]
public record ObjectId(int Id);
További információért lásd: Hogyan írjunk egyéni konvertereket.
Megadott típusok kizárása a modellkötésből
A modellkötési és érvényesítési rendszerek viselkedését a ModelMetadatavezérli. Ön testre szabhatja a ModelMetadata egy részlet szolgáltató hozzáadásával az MvcOptions.ModelMetadataDetailsProviders-hez. A beépített részletek szolgáltatói a modellkötés letiltására vagy a megadott típusok érvényesítésére használhatók.
Ha le szeretné tiltani a modellkötést egy meghatározott típus összes modelljén, adjon hozzá egy ExcludeBindingMetadataProvider a Program.cs-ben. Ha például le szeretné tiltani a modellkötést az összes System.Versiontípusú modellen:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Ha le szeretné tiltani az ellenőrzést egy megadott típusú tulajdonságon, adjon hozzá egy SuppressChildValidationMetadataProvider a Program.cs-be. Például a System.Guidtípusú tulajdonságok érvényesítésének letiltásához:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.ModelMetadataDetailsProviders.Add(
new ExcludeBindingMetadataProvider(typeof(Version)));
options.ModelMetadataDetailsProviders.Add(
new SuppressChildValidationMetadataProvider(typeof(Guid)));
});
Egyéni modellek összekötői
A modellkötés kibővítéséhez írjon egy egyéni modellkötőt, és a [ModelBinder] attribútummal válassza ki azt egy meghatározott célhoz. Tudjon meg többet az egyéni modellkötésről.
Manuális modellkötés
A modellkötés manuálisan hívható meg a TryUpdateModelAsync metódus használatával. A metódus ControllerBase és PageModel osztályokban is definiálva van. A metódustúlterhelésekkel lehetősége van megadni a használni kívánt előtagot és értékszolgáltatót. A metódus false ad vissza, ha a modellkötés meghiúsul. Íme egy példa:
if (await TryUpdateModelAsync(
newInstructor,
"Instructor",
x => x.Name, x => x.HireDate!))
{
_instructorStore.Add(newInstructor);
return RedirectToPage("./Index");
}
return Page();
TryUpdateModelAsync értékszolgáltatókat használ az űrlap törzséből, a lekérdezési sztringből és az útvonaladatok lekéréséhez.
TryUpdateModelAsync általában a következő:
- A Razor Lapok és MVC-alkalmazásokhoz használható vezérlőkkel és nézetekkel, hogy megakadályozza a túlzott közzétételt.
- Egy webes API-val nem használható, kivéve ha űrlapadatokból, lekérdezési karakterláncokból vagy útvonaladatokból történik a felhasználás. A JSON-t használó webes API-végpontok bemeneti formázókkal deszerializálják a kérelem törzsét egy objektumba.
További információért lásd TryUpdateModelAsync.
[FromServices] attribútum
Az attribútum neve az adatforrást meghatározó modellkötési attribútumok mintáját követi. De nem az értékszolgáltatótól származó adatok kötéséről van szó. Egy típuspéldányt kap a függőséginjektálási tárolóból. Célja, hogy alternatívát biztosítson a konstruktorinjektáláshoz, ha csak egy adott módszer meghívása esetén van szüksége szolgáltatásra.
Ha egy ilyen típusú példány nincs regisztrálva a függőséginjektálási tárolóban, az alkalmazás kivételt jelez a paraméter kötésekor. A paraméter opcionálissá tétele érdekében használja az alábbi módszerek egyikét:
- A paraméter null értékűvé tétele.
- Állítson be egy alapértelmezett értéket a paraméterhez.
Null értékű paraméterek esetén győződjön meg arról, hogy a paraméter nem null a hozzáférés előtt.
További erőforrások
- Mintakód megtekintése vagy letöltése (hogyan töltsd le)
- Modell-ellenőrzés az ASP.NET Core MVC-ben
- Egyéni modell kötése ASP.NET Core
Ez a cikk bemutatja, hogy mi a modellkötés, hogyan működik, és hogyan szabhatja testre a viselkedését.
Mintakód megtekintése vagy letöltése (hogyan töltsük le).
Mi az a modellkötés?
A vezérlők és Razor lapok HTTP-kérelmekből származó adatokkal dolgoznak. Az útvonaladatok például megadhatnak egy rekordkulcsot, a közzétett űrlapmezők pedig értékeket adhatnak a modell tulajdonságaihoz. A kód megírása ezeknek az értékeknek a lekéréséhez és a sztringekből .NET-típusokká való konvertálásához fárasztó és hibalehetőségekkel járna. A modellkötés automatizálja ezt a folyamatot. A modellkötési rendszer:
- Adatokat kér le különböző forrásokból, például útvonaladatokból, űrlapmezőkből és lekérdezési sztringekből.
- Az adatokat a vezérlőknek és Razor oldalaknak biztosítja a metódusparaméterek és a nyilvános tulajdonságok útján.
- A sztringadatokat .NET-típusokká alakítja.
- Frissíti az összetett típusok tulajdonságait.
Example
Tegyük fel, hogy a következő műveleti módszerrel rendelkezik:
[HttpGet("{id}")]
public ActionResult<Pet> GetById(int id, bool dogsOnly)
Az alkalmazás a következő URL-címmel kap egy kérést:
http://contoso.com/api/pets/2?DogsOnly=true
A modellkötés a következő lépéseken megy keresztül, miután az útválasztási rendszer kiválasztotta a műveletmetódust:
- Megkeresi a
GetByIdelső paraméterét , amely egyidnevű egész szám. - Megvizsgálja a HTTP-kérelemben elérhető forrásokat, és megkeresi a
id= "2" értéket az útvonaladatokban. - A "2" sztringet 2 egész számmá alakítja.
- Megkeresi a
GetByIdkövetkező paraméterét , egydogsOnlynevű logikai értéket. - Megvizsgálja a forrásokat, és megkeresi a "DogsOnly=true" kifejezést a lekérdezési sztringben. A névegyeztetés nem érzékeny a kis- és nagybetűkre.
- Az "true" sztringet booleán típusú
trueértékké alakítja át.
A keretrendszer ezután meghívja a GetById metódust, és a 2-t adja át a id paraméternek, valamint true-t adja át a dogsOnly paraméternek.
Az előző példában a modellkötési célok egyszerű típusú metódusparaméterek. A célok egy összetett típus tulajdonságai is lehetnek. Az egyes tulajdonságok sikeres kötése után modellérvényesítési történik az adott tulajdonsághoz. A modellhez kötött adatok nyilvántartása, valamint bármely kötési vagy érvényesítési hiba a ControllerBase.ModelState vagy PageModel.ModelStatetárolva van. Annak kiderítéséhez, hogy a folyamat sikeres volt-e, az alkalmazás ellenőrzi a ModelState.IsValid jelzőt.
Targets
A modellkötés a következő típusú célok értékeit próbálja megtalálni:
- Annak a vezérlőműveleti metódusnak a paraméterei, amelyekre a kérések irányítva lesznek.
- Azon Razor Pages-kezelő metódus paraméterei, amelyekhez a kérések irányítva lesznek.
- Egy vezérlő vagy
PageModelosztály nyilvános tulajdonságai, ha az attribútumok meg vannak adva.
[BindProperty] attribútum
Egy vezérlő vagy PageModel osztály nyilvános tulajdonságára alkalmazható, hogy a modellkötés a tulajdonságot célozza:
public class EditModel : InstructorsPageModel
{
[BindProperty]
public Instructor Instructor { get; set; }
[BindProperties] attribútum
A ASP.NET Core 2.1-ben vagy újabb verzióiban érhető el. Egy vezérlőre vagy PageModel osztályra alkalmazható, hogy a modellkötés az osztály összes nyilvános tulajdonságát megcélzhassa:
[BindProperties(SupportsGet = true)]
public class CreateModel : InstructorsPageModel
{
public Instructor Instructor { get; set; }
Modellkötés HTTP GET-kérelmekhez
Alapértelmezés szerint a http GET-kérések nem kötik a tulajdonságokat. A GET-kéréshez általában csak egy rekordazonosító paraméter szükséges. A rekordazonosítóval megkereshető az elem az adatbázisban. Ezért nincs szükség olyan tulajdonság kötésére, amely a modell egy példányát tartalmazza. Olyan esetekben, amikor a GET-kérelmekből származó adatokhoz kötött tulajdonságokat szeretne, állítsa a SupportsGet tulajdonságot true:
[BindProperty(Name = "ai_user", SupportsGet = true)]
public string ApplicationInsightsCookie { get; set; }
Sources
A modellkötés alapértelmezés szerint kulcs-érték párok formájában kéri le az adatokat egy HTTP-kérelem következő forrásaiból:
- Űrlapmezők
- A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
- Útvonal adatok
- Lekérdezési sztringparaméterek
- Feltöltött fájlok
Minden célparaméter vagy tulajdonság esetében a forrásokat az előző listában megadott sorrendben ellenőrzi a rendszer. Van néhány kivétel:
- Az útvonaladatok és a lekérdezési sztringértékek csak egyszerű típusok esetén használhatók.
- A feltöltött fájlok csak olyan céltípusokhoz vannak kötve, amelyek
IFormFilevagyIEnumerable<IFormFile>implementálnak.
Ha az alapértelmezett forrás helytelen, használja az alábbi attribútumok egyikét a forrás megadásához:
-
[FromQuery]– Lekéri a lekérdezési sztring értékeit. -
[FromRoute]– Lekéri az útvonaladatok értékeit. -
[FromForm]– Lekéri a beküldött űrlapmezők értékeit. -
[FromBody]– Lekéri az értékeket a kérelem törzséből. -
[FromHeader]– HTTP-fejlécekből származó értékeket kap.
Ezek az attribútumok:
A modelltulajdonságok egyenként vannak hozzáadva (nem a modellosztályhoz), mint az alábbi példában:
public class Instructor { public int ID { get; set; } [FromQuery(Name = "Note")] public string NoteFromQueryString { get; set; }Igény szerint elfogadhat egy modellnévértéket a konstruktorban. Ez a beállítás abban az esetben van megadva, ha a tulajdonság neve nem egyezik meg a kérelemben szereplő értékkel. A kérés értéke lehet például egy fejléc, amelynek nevében egy kötőjel szerepel, ahogyan az alábbi példában is látható:
public void OnGet([FromHeader(Name = "Accept-Language")] string language)
[FromBody] attribútum
Alkalmazza a [FromBody] attribútumot egy paraméterre, hogy a tulajdonságait egy HTTP-kérés törzséből töltse ki. A ASP.NET Core futtatókörnyezet egy bemeneti formázónak delegálja a törzs olvasásának felelősségét. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
Ha [FromBody] komplex típusú paraméterre van alkalmazva, a rendszer figyelmen kívül hagyja a tulajdonságokra alkalmazott kötési forrásattribútumokat. Az alábbi Create művelet például azt határozza meg, hogy a pet paramétere ki legyen töltve a törzsből:
public ActionResult<Pet> Create([FromBody] Pet pet)
A Pet osztály azt határozza meg, hogy a Breed tulajdonsága egy lekérdezési sztringparaméterből legyen feltöltve:
public class Pet
{
public string Name { get; set; }
[FromQuery] // Attribute is ignored.
public string Breed { get; set; }
}
Az előző példában:
- A
[FromQuery]attribútum figyelmen kívül lesz hagyva. - A
Breedtulajdonság nincs kitöltve lekérdezési sztringparaméterből.
A bemeneti formázók csak a törzset olvassák, és nem értik a kötés forrásattribútumait. Ha a törzsben talál egy megfelelő értéket, a rendszer ezt az értéket használja a Breed tulajdonság feltöltéséhez.
Ne alkalmazza a [FromBody] műveletmetódusonként egynél több paraméterre. Miután a kérelemfolyamot beolvassa egy bemeneti formázó, már nem olvasható újra más [FromBody] paraméterek kötéséhez.
További források
A forrásadatokat értékszolgáltatókadják meg a modellkötési rendszernek. Írhat és regisztrálhat olyan egyéni értékszolgáltatókat, amelyek más forrásokból származó modellkötési adatokat kérnek le. Előfordulhat például, hogy cookie-kból vagy munkamenet-állapotból szeretne adatokat. Adatok lekérése új forrásból:
- Hozzon létre egy
IValueProvidermegvalósító osztályt. - Hozzon létre egy
IValueProviderFactorymegvalósító osztályt. - Regisztrálja a gyári osztályt a
Startup.ConfigureServices-ban.
A mintaalkalmazás tartalmaz egy értékszolgáltatói és gyári példát, amely a cookie-kból szerez be értékeket. Íme a regisztrációs kód 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();
A megjelenített kód az egyéni értékszolgáltatót az összes beépített értékszolgáltató után helyezi el. Ahhoz, hogy ez legyen az első a listában, Insert(0, new CookieValueProviderFactory())helyett hívja meg Add.
Nincs forrás egy modelltulajdonsághoz
Alapértelmezés szerint nem jön létre modellállapot-hiba, ha nem található érték egy modelltulajdonsághoz. A tulajdonság értéke null vagy alapértelmezett érték:
- A null értéket is felvevő egyszerű típusok
null-re vannak állítva. - A nem null értékű értéktípusok értéke be van állítva
default(T). Egyint idparaméter például 0 értékre van állítva. - Összetett típusok esetén a modellkötés az alapértelmezett konstruktor használatával hoz létre egy példányt tulajdonságok megadása nélkül.
- A tömbök
Array.Empty<T>()értékre vannak beállítva, kivéve, hogy abyte[]tömböknullértékre vannak beállítva.
Ha a modell állapotát érvényteleníteni kell, ha nem található semmi a modelltulajdonság űrlapmezőiben, használja a [BindRequired] attribútumot.
Vegye figyelembe, hogy ez a [BindRequired] viselkedés a közzétett űrlapadatokból származó modellkötésekre vonatkozik, nem pedig a kérelem törzsében lévő JSON- vagy XML-adatokra. Az igénylés törzsadatait a bemeneti formázókkezelik.
Típuskonvertálási hibák
Ha talál egy forrást, de nem konvertálható céltípussá, a modell állapota érvénytelenként van megjelölve. A célparaméter vagy tulajdonság null értékűre vagy alapértelmezett értékre van állítva az előző szakaszban leírtak szerint.
A [ApiController] attribútummal rendelkező API-vezérlőben az érvénytelen modellállapot automatikus HTTP 400-választ eredményez.
Razor lapon jelenítse meg újra a lapot egy hibaüzenettel:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
_instructorsInMemoryStore.Add(Instructor);
return RedirectToPage("./Index");
}
Az ügyféloldali ellenőrzés a legtöbb rossz adatot elkapja, amelyeket egyébként egy Razor Pages-űrlapra küldenének. Ez az ellenőrzés megnehezíti az előző kiemelt kód aktiválását. A mintaalkalmazás tartalmaz egy Küldés érvénytelen dátummal gombot, amely rossz adatokat helyez el a Felvétel időpontja mezőben, és elküldi az űrlapot. Ez a gomb bemutatja, hogyan működik az oldal újbóli megjelenítésére szolgáló kód adatkonvertálási hibák esetén.
Ha az előző kód visszajátssza a lapot, az érvénytelen bemenet nem jelenik meg az űrlapmezőben. Ennek az az oka, hogy a modelltulajdonság null értékűre vagy alapértelmezett értékre lett beállítva. Az érvénytelen bemenet megjelenik egy hibaüzenetben. Ha azonban újra szeretné megjeleníteni a hibás adatokat az űrlapmezőben, fontolja meg a modell tulajdonságának karakterláncként való beállítását, és végezze el kézzel az adatkonvertálást.
Ugyanez a stratégia akkor ajánlott, ha nem szeretné, hogy a típuskonvertálási hibák modellállapot-hibákat eredményeznek. Ebben az esetben változtassa a modell tulajdonságát stringgé.
Egyszerű típusok
A modellkötő által forrássztringekké átalakítható egyszerű típusok a következők:
- Boolean
- Bájt, SByte
- Char
- DateTime
- DateTimeOffset
- Decimal
- Double
- Enum
- Guid
- Int16, Int32, Int64
- Single
- TimeSpan
- UInt16, UInt32, UInt64
- Uri
- Version
Összetett típusok
Egy összetett típusnak nyilvános alapértelmezett konstruktorsal és nyilvános írható tulajdonságokkal kell rendelkeznie a kötéshez. Modellkötés esetén az osztály példányosítása a nyilvános alapértelmezett konstruktor használatával történik.
Az összetett típus minden tulajdonsága esetében a modellkötés a névminta forrásain prefix.property_name. Ha semmi sem található, csak property_name keres az előtag nélkül.
A paraméterhez való kötésnél az előtag a paraméter neve. Egy PageModel nevű nyilvános tulajdonsághoz való kötés esetén az előtag a tulajdonság neve. Egyes attribútumok Prefix tulajdonságot használnak, amelyekkel felülbírálhatja a paraméter vagy a tulajdonságnév alapértelmezett használatát.
Tegyük fel például, hogy az összetett típus a következő Instructor osztály:
public class Instructor
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
}
Előtag = paraméternév
Ha a kötendő modell egy instructorToUpdatenevű paraméter:
public IActionResult OnPost(int? id, Instructor instructorToUpdate)
A modellkötés a kulcs instructorToUpdate.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Előtag = tulajdonságnév
Ha a kötendő modell a vezérlő Instructor nevű tulajdonsága vagy a PageModel osztály:
[BindProperty]
public Instructor Instructor { get; set; }
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Egyéni előtag
Ha a kötendő modell egy instructorToUpdate nevű paraméter, és egy Bind attribútum Instructor határoz meg előtagként:
public IActionResult OnPost(
int? id, [Bind(Prefix = "Instructor")] Instructor instructorToUpdate)
A modellkötés a kulcs Instructor.IDforrásainak átnézésével kezdődik. Ha ez nem található, előtag nélkül keres ID.
Attribútumok összetett típusú célokhoz
Összetett típusok modellkötésének szabályozásához számos beépített attribútum érhető el:
[Bind][BindRequired][BindNever]
Warning
Ezek az attribútumok hatással vannak a modellkötésre, ha a közzétett űrlapadatok az értékek forrása. Nincsenek hatással a bemeneti formázók működésére, melyek feldolgozzák a közzétett JSON- és XML-kérelemtörzseket. A bemeneti formázók a cikk későbbi részében vannak kifejtve.
[Kötés] attribútum
Alkalmazható osztályra vagy metódusparaméterre. Meghatározza, hogy a modell mely tulajdonságait kell szerepeltetni a modellkötésben.
[Bind] nem hatással a bemeneti formázókra.
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve, amikor bármely kezelőt vagy műveletmetódust meghívnak:
[Bind("LastName,FirstMidName,HireDate")]
public class Instructor
Az alábbi példában csak a Instructor modell megadott tulajdonságai vannak megkötve a OnPost metódus meghívásakor:
[HttpPost]
public IActionResult OnPost([Bind("LastName,FirstMidName,HireDate")] Instructor instructor)
A [Bind] attribútum használható a forgatókönyvek létrehozásakor a túlzott adatküldés elleni védelemre. Szerkesztési forgatókönyvekben nem működik jól, mert a kizárt tulajdonságok értéke null vagy alapértelmezett érték, ahelyett, hogy változatlan marad. A túlpostolás elleni védelem érdekében a [Bind] attribútum helyett a nézetmodellek használata ajánlott. További információ: biztonsági megjegyzés atúlpostolásáról.
[ModelBinder] attribútum
ModelBinderAttribute alkalmazhatók típusokra, tulajdonságokra vagy paraméterekre. Lehetővé teszi az adott példány vagy típus kötéséhez használt modellkötő típusának megadását. Például:
[HttpPost]
public IActionResult OnPost([ModelBinder(typeof(MyInstructorModelBinder))] Instructor instructor)
A [ModelBinder] attribútum egy tulajdonság vagy paraméter nevének módosítására is használható modellkötés esetén:
public class Instructor
{
[ModelBinder(Name = "instructor_id")]
public string Id { get; set; }
public string Name { get; set; }
}
[BindRequired] attribútum
Csak a modelltulajdonságokra alkalmazható, a metódusparaméterekre nem. Ha a modell tulajdonságához nem lehetséges a kötés, a modellkötés modellállapot-hibát ad hozzá. Íme egy példa:
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; }
Lásd még a [Required] attribútumának ismertetését.
[BindNever] attribútum
Csak a modelltulajdonságokra alkalmazható, a metódusparaméterekre nem. Megakadályozza azt, hogy a modell kötési folyamata beállítsa a modell tulajdonságát. Íme egy példa:
public class InstructorWithDictionary
{
[BindNever]
public int ID { get; set; }
Collections
Az egyszerű típusok gyűjteményét tartalmazó célok esetében a modellkötés a parameter_name vagy property_nameegyezéseket keres. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a kötendő paraméter egy
selectedCoursesnevű tömb:public IActionResult OnPost(int? id, int[] selectedCourses)Az űrlap- vagy lekérdezési sztringadatok az alábbi formátumok egyikében lehetnek:
selectedCourses=1050&selectedCourses=2000selectedCourses[0]=1050&selectedCourses[1]=2000[0]=1050&[1]=2000selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b[a]=1050&[b]=2000&index=a&index=bKerülje egy
indexvagyIndexnevű paraméter vagy tulajdonság kötését, ha az egy gyűjteményérték mellett található. A modellkötés megpróbálja aindex-t gyűjteményindexként használni, ami helytelen kötéshez vezethet. Vegyük például a következő műveletet:public IActionResult Post(string index, List<Product> products)Az előző kódban a
indexlekérdezési sztring paraméter aindexmetódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi aindexparamétert, vagy modellkötési attribútumot használ a kötés konfigurálásához, elkerüli ezt a problémát:public IActionResult Post(string productIndex, List<Product> products)A következő formátum csak űrlapadatokban támogatott:
selectedCourses[]=1050&selectedCourses[]=2000Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a
selectedCoursesparaméternek:- selectedCourses[0]=1050
- selectedCourses[1]=2000
Alsó indexszámokat használó adatformátumoknak (... [0] ... [1] ...) meg kell győződniük arról, hogy nullától kezdve egymás után vannak számozva. Ha van rés az alsó indexszámozásban, a rendszer figyelmen kívül hagyja a rést követő összes elemet. Ha például az alsó indexek 0 és 1 helyett 0 és 2, akkor a második elemet figyelmen kívül hagyják.
Dictionaries
A Dictionary-célok esetében a modellkötés a parameter_name vagy property_nametalálatokat keresi. Ha nem található egyezés, az előtag elhagyásával keresi az egyik támogatott formátumot. Például:
Tegyük fel, hogy a célparaméter egy
Dictionary<int, string>nevűselectedCourses:public IActionResult OnPost(int? id, Dictionary<int, string> selectedCourses)A közzétett űrlap- vagy lekérdezési sztringadatok az alábbi példák egyikéhez hasonlóan nézhetnek ki:
selectedCourses[1050]=Chemistry&selectedCourses[2000]=Economics[1050]=Chemistry&selectedCourses[2000]=EconomicsselectedCourses[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=EconomicsAz összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a
selectedCoursesparaméternek:- selectedCourses["1050"]="Chemistry"
- selectedCourses["2000"]="Economics"
Konstruktorkötés és rekordtípusok
A modellkötéshez az összetett típusok paraméter nélküli konstruktort igényelnek. Mind System.Text.Json, mind Newtonsoft.Json alapú bemeneti formázók támogatják a paraméter nélküli konstruktor nélküli osztályok deszerializálását.
A C# 9 rekordtípusokat vezet be, amelyek segítségével tömören ábrázolhatók a hálózaton keresztüli adatok. ASP.NET Core támogatja a modellkötést és a rekordtípusok érvényesítését egyetlen konstruktor használatával:
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>
Rekordtípusok ellenőrzésekor a futtatókörnyezet a tulajdonságok helyett a paramétereken keres kötési és érvényesítési metaadatokat.
A keretrendszer lehetővé teszi a rekordtípusok kötését és érvényesítését:
public record Person([Required] string Name, [Range(0, 100)] int Age);
Az előző működéshez a típusnak a következőnek kell lennie:
- Legyen rekordtípus.
- Pontosan egy nyilvános konstruktor.
- Olyan paramétereket tartalmaz, amelyek azonos nevű és típusú tulajdonsággal rendelkeznek. A nevek kis- és nagybetűk szerint nem különbözhetnek.
Paraméter nélküli konstruktorok nélküli POCO-k
Azok a POCO-k, amelyek nem rendelkeznek paraméter nélküli konstruktorokkal, nem köthetők.
Az alábbi kód kivételt eredményez, amely szerint a típusnak paraméter nélküli konstruktort kell tartalmaznia:
public class Person(string Name)
public record Person([Required] string Name, [Range(0, 100)] int Age)
{
public Person(string Name) : this (Name, 0);
}
Rekordtípusok manuálisan létrehozott konstruktorokkal
Az elsődleges konstruktorokhoz hasonló, manuálisan létrehozott konstruktorokkal rendelkező rekordtípusok működnek
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; }
}
Rekordtípusok, érvényesítési és kötési metaadatok
Rekordtípusok esetében a paraméterek érvényesítési és kötési metaadatait használja a rendszer. A tulajdonságok metaadatai figyelmen kívül lesznek hagyva
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; }
}
Érvényesítés és metaadatok
Az ellenőrzés metaadatokat használ a paraméteren, de a tulajdonság használatával olvassa be az értéket. Az elsődleges konstruktorok esetében a kettő azonos lenne. Vannak azonban módszerek a legyőzésére:
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);`
}
A TryUpdateModel nem frissíti a rekordtípus paramétereit
public record Person(string Name)
{
public int Age { get; set; }
}
var person = new Person("initial-name");
TryUpdateModel(person, ...);
Ebben az esetben az MVC nem próbálja meg újra megkötni Name. A Age azonban frissíthető
Modellkötés útvonaladatainak és lekérdezési sztringjeinek globalizációs viselkedése
A ASP.NET Fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató:
- Értékeket invariáns kultúraként kezelni.
- Arra számít, hogy az URL-címek kulturális invariánsak.
Ezzel szemben az űrlapadatokból származó értékek kultúraérzékeny átalakításon mennek keresztül. Az URL-címek szándékosan úgy vannak kialakítva, hogy megoszthatóak legyenek az egyes területek között.
A ASP.NET fő útvonalérték-szolgáltató és a lekérdezési sztringérték-szolgáltató kulturális szempontból érzékeny átalakításon megy keresztül:
- Származzon a IValueProviderFactory-ból
- Másolja az alábbi kódot QueryStringValueProviderFactory vagy RouteValueValueProviderFactory
- Cserélje le az értékszolgáltató konstruktorának átadott kulturálisCultureInfo.CurrentCulture
- Cserélje le az alapértelmezett értékszolgáltató gyárat az MVC-beállításokban az Ön új értékszolgáltatójára.
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ális adattípusok
Vannak speciális adattípusok, amelyeket a modellkötés képes kezelni.
IFormFile és IFormFileCollection
A HTTP-kérelemben szereplő feltöltött fájl. Támogatott a IEnumerable<IFormFile> több fájlhoz is.
CancellationToken
A műveletek opcionálisan paraméterként köthetnek egy CancellationToken. Ez köti RequestAborted, amely jelzi, ha a HTTP-kérés alapjául szolgáló kapcsolat megszakad. A műveletek ezzel a paraméterrel megszakíthatják a vezérlőműveletek részeként végrehajtott hosszú ideig futó aszinkron műveleteket.
FormCollection
Az összes érték lekérésére szolgál a közzétett űrlapadatokból.
Bemeneti formázók
A kérelem törzsében lévő adatok lehetnek JSON-, XML- vagy egyéb formátumúak. Az adatok elemzéséhez a modellkötés egy bemeneti formázó használ, amely egy adott tartalomtípus kezelésére van konfigurálva. Alapértelmezés szerint a ASP.NET Core JSON-alapú bemeneti formázókat tartalmaz a JSON-adatok kezeléséhez. Más tartalomtípusokhoz más formátumkészítőket is hozzáadhat.
ASP.NET Core a attribútum alapján választja ki a bemeneti formázókat. Ha nincs attribútum, akkor a Content-Type fejlécet használja.
A beépített XML-bemeneti formázók használata:
Telepítse a
Microsoft.AspNetCore.Mvc.Formatters.XmlNuGet-csomagot.Hívja a
Startup.ConfigureServices, AddXmlSerializerFormatters vagy AddXmlDataContractSerializerFormattersszámot.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();Alkalmazza a
Consumesattribútumot olyan vezérlőosztályokra vagy műveleti módszerekre, amelyeknek XML-t kell várniuk a kérelem törzsében.[HttpPost] [Consumes("application/xml")] public ActionResult<Pet> Create(Pet pet)További információ: XML-szerializálás bemutatása.
Modellkötés testreszabása bemeneti formázókkal
A bemeneti formázó teljes felelősséget vállal azért, hogy adatokat olvas be a kérelem törzséből. A folyamat testreszabásához konfigurálja a bemeneti formázó által használt API-kat. Ez a szakasz azt ismerteti, hogyan szabhatja testre a System.Text.Json-alapú bemeneti formátumot a ObjectIdnevű egyéni típus megértéséhez.
Fontolja meg a következő modellt, amely egy ObjectIdnevű egyéni Id tulajdonságot tartalmaz:
public class ModelWithObjectId
{
public ObjectId Id { get; set; }
}
Ha testreszabni szeretné a modellkötési folyamatot System.Text.Jsonhasználatakor, hozzon létre egy osztályt, amely származik 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);
}
}
Egyéni konverter használatához alkalmazza a JsonConverterAttribute attribútumot a típusra. Az alábbi példában a ObjectId típus egyéni konverterként ObjectIdConverter van konfigurálva:
[JsonConverter(typeof(ObjectIdConverter))]
public struct ObjectId
{
public ObjectId(int id) =>
Id = id;
public int Id { get; }
}
További információért lásd: Hogyan írjunk egyéni konvertereket.
Megadott típusok kizárása a modellkötésből
A modellkötési és érvényesítési rendszerek viselkedését a ModelMetadatavezérli. Ön testre szabhatja a ModelMetadata egy részlet szolgáltató hozzáadásával az MvcOptions.ModelMetadataDetailsProviders-hez. A beépített részletek szolgáltatói a modellkötés letiltására vagy a megadott típusok érvényesítésére használhatók.
Ha le szeretné tiltani a modellkötést egy meghatározott típus összes modelljén, adjon hozzá egy ExcludeBindingMetadataProvider a Startup.ConfigureServices-ben. Ha például le szeretné tiltani a modellkötést az összes System.Versiontípusú modellen:
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();
Ha le szeretné tiltani az ellenőrzést egy megadott típusú tulajdonságon, adjon hozzá egy SuppressChildValidationMetadataProvider a Startup.ConfigureServices-be. Például a System.Guidtípusú tulajdonságok érvényesítésének letiltásához:
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();
Egyéni modellek összekötői
A modellkötés kibővítéséhez írjon egy egyéni modellkötőt, és a [ModelBinder] attribútummal válassza ki azt egy meghatározott célhoz. Tudjon meg többet az egyéni modellkötésről.
Manuális modellkötés
A modellkötés manuálisan hívható meg a TryUpdateModelAsync metódus használatával. A metódus ControllerBase és PageModel osztályokban is definiálva van. A metódustúlterhelésekkel lehetősége van megadni a használni kívánt előtagot és értékszolgáltatót. A metódus false ad vissza, ha a modellkötés meghiúsul. Íme egy példa:
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 értékszolgáltatókat használ az űrlap törzséből, a lekérdezési sztringből és az útvonaladatok lekéréséhez.
TryUpdateModelAsync általában a következő:
- A Razor Lapok és MVC-alkalmazásokhoz használható vezérlőkkel és nézetekkel, hogy megakadályozza a túlzott közzétételt.
- Egy webes API-val nem használható, kivéve ha űrlapadatokból, lekérdezési karakterláncokból vagy útvonaladatokból történik a felhasználás. A JSON-t használó webes API-végpontok bemeneti formázókkal deszerializálják a kérelem törzsét egy objektumba.
További információért lásd TryUpdateModelAsync.
[FromServices] attribútum
Az attribútum neve az adatforrást meghatározó modellkötési attribútumok mintáját követi. De nem az értékszolgáltatótól származó adatok kötéséről van szó. Egy típuspéldányt kap a függőséginjektálási tárolóból. Célja, hogy alternatívát biztosítson a konstruktorinjektáláshoz, ha csak egy adott módszer meghívása esetén van szüksége szolgáltatásra.