Megosztás a következőn keresztül:


Modellkötés a ASP.NET Core-ban

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 egy idnevű 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 , egy dogsOnlynevű 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 PageModel osztá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:

  1. Űrlapmezők
  2. A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
  3. Útvonal adatok
  4. Lekérdezési sztringparaméterek
  5. 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 IFormFile vagy IEnumerable<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 Breed tulajdonsá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). Egy int id paramé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 a byte[] tömbök nullé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:

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 DateRange objektummá
  • A modellkötő a IParsable<TSelf>.TryParse metódust használja a DateRangekö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:

  • Id 100értékre van állítva.
  • Name nullértékre van állítva. A modellkötés Instructor.Name vár, mert az előző lekérdezési paraméterben Instructor.Id haszná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=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    

    Kerülje egy index vagy Index nevű 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 a index-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 index lekérdezési sztring paraméter a index metódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi a index paramé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[]=2000
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a selectedCourses paramé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]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a selectedCourses paramé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:

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:

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

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 egy idnevű 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 , egy dogsOnlynevű 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 PageModel osztá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:

  1. Űrlapmezők
  2. A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
  3. Útvonal adatok
  4. Lekérdezési sztringparaméterek
  5. 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 IFormFile vagy IEnumerable<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 Breed tulajdonsá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). Egy int id paramé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 a byte[] tömbök nullé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:

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 DateRange objektummá
  • A modellkötő a IParsable<TSelf>.TryParse metódust használja a DateRangekö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:

  • Id 100értékre van állítva.
  • Name nullértékre van állítva. A modellkötés Instructor.Name vár, mert az előző lekérdezési paraméterben Instructor.Id haszná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=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    

    Kerülje egy index vagy Index nevű 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 a index-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 index lekérdezési sztring paraméter a index metódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi a index paramé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[]=2000
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a selectedCourses paramé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]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a selectedCourses paramé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:

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:

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

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 egy idnevű 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 , egy dogsOnlynevű 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 PageModel osztá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:

  1. Űrlapmezők
  2. A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
  3. Útvonal adatok
  4. Lekérdezési sztringparaméterek
  5. 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 IFormFile vagy IEnumerable<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 Breed tulajdonsá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). Egy int id paramé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 a byte[] tömbök nullé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:

Ö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:

  • Id 100értékre van állítva.
  • Name nullértékre van állítva. A modellkötés Instructor.Name vár, mert az előző lekérdezési paraméterben Instructor.Id haszná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=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    

    Kerülje egy index vagy Index nevű 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 a index-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 index lekérdezési sztring paraméter a index metódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi a index paramé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[]=2000
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a selectedCourses paramé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]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a selectedCourses paramé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:

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:

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

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 egy idnevű 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 , egy dogsOnlynevű 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 PageModel osztá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:

  1. Űrlapmezők
  2. A kérelem törzse (Az [ApiController] attribútummal rendelkező vezérlők esetében.)
  3. Útvonal adatok
  4. Lekérdezési sztringparaméterek
  5. 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 IFormFile vagy IEnumerable<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 Breed tulajdonsá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). Egy int id paramé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 a byte[] tömbök nullé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:

Ö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=2000 
    
    selectedCourses[0]=1050&selectedCourses[1]=2000
    
    [0]=1050&[1]=2000
    
    selectedCourses[a]=1050&selectedCourses[b]=2000&selectedCourses.index=a&selectedCourses.index=b
    
    [a]=1050&[b]=2000&index=a&index=b
    

    Kerülje egy index vagy Index nevű 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 a index-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 index lekérdezési sztring paraméter a index metódusparaméterhez kapcsolódik, és a termékgyűjtemény kötésére is használható. Ha átnevezi a index paramé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[]=2000
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló tömböt ad át a selectedCourses paramé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]=Economics
    
    selectedCourses[0].Key=1050&selectedCourses[0].Value=Chemistry&
    selectedCourses[1].Key=2000&selectedCourses[1].Value=Economics
    
    [0].Key=1050&[0].Value=Chemistry&[1].Key=2000&[1].Value=Economics
    
  • Az összes fenti példaformátum esetében a modellkötés két elemből álló szótárat ad át a selectedCourses paramé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:

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.Xml NuGet-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 Consumes attribú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.

További erőforrások