Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Készítette : Kirk Larkin
A modellkötés lehetővé teszi, hogy a vezérlőműveletek a HTTP-kérések helyett közvetlenül modelltípusokkal (metódusargumentumokként átadva) működjenek. A bejövő kérelmek adatai és az alkalmazásmodellek közötti leképezést modellkötők kezelik. A fejlesztők egyéni modellkötők implementálásával bővíthetik a beépített modellkötési funkciókat (bár általában nincs szükség arra, hogy saját szolgáltatót írjanak).
Mintakód megtekintése vagy letöltése (hogyan töltsd le)
Alapértelmezett modellkötő korlátozások
Az alapértelmezett modellkötők támogatják a legtöbb gyakori .NET Core-adattípust, és a legtöbb fejlesztő igényeit kielégítik. Azt várják, hogy a kérés szövegalapú bemenetét közvetlenül a modelltípusokhoz kötik. Előfordulhat, hogy a kötés előtt át kell alakítania a bemenetet. Ha például rendelkezik egy olyan kulccsal, amellyel modelladatokat kereshet. Saját modellkötő használatával lekérheti az adatokat a kulcs alapján.
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.
A modellkötő által sztringekből konvertálható típusok listája az Egyszerű típusok című részben található.
Mielőtt saját egyéni modellkötőt hozna létre, érdemes áttekinteni, hogy a meglévő modellkötők hogyan vannak implementálva. ByteArrayModelBinder A base64 kódolású sztringek bájttömbökké alakításához használható. A bájttömböket gyakran fájlokként vagy adatbázis BLOB-mezőkként tárolják.
A ByteArrayModelBinder használata
A Base64 kódolású sztringek bináris adatok megjelenítésére használhatók. Egy kép például sztringként kódolható. A minta egy képet tartalmaz alap64 kódolású sztringként aBase64String.txt.
ASP.NET Core MVC képes egy base64-kódolt karakterláncot felvenni, és ByteArrayModelBinder segítségével bájttömbbé alakítani. A ByteArrayModelBinderProvider az byte[] argumentumokat a ByteArrayModelBinder-ra/-re képezi le:
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(byte[]))
{
var loggerFactory = context.Services.GetRequiredService<ILoggerFactory>();
return new ByteArrayModelBinder(loggerFactory);
}
return null;
}
Saját egyéni modellkötés létrehozásakor implementálhatja a saját IModelBinderProvider típusát, vagy használhatja a ModelBinderAttribute.
Az alábbi példa bemutatja, hogyan lehet egy base64-kódolású stringet ByteArrayModelBinder segítségével byte[] formátummá alakítani, és az eredményt fájlba menteni.
[HttpPost]
public void Post([FromForm] byte[] file, string filename)
{
// Don't trust the file name sent by the client. Use
// Path.GetRandomFileName to generate a safe random
// file name. _targetFilePath receives a value
// from configuration (the appsettings.json file in
// the sample app).
var trustedFileName = Path.GetRandomFileName();
var filePath = Path.Combine(_targetFilePath, trustedFileName);
if (System.IO.File.Exists(filePath))
{
return;
}
System.IO.File.WriteAllBytes(filePath, file);
}
Ha szeretné, hogy a kódkommentárok angolon kívül más nyelvekre is le legyenek fordítva, jelezze nekünk a GitHub vitafórumkérdésénél.
Egy base64 kódolású sztringet postázhat az előző API-metódushoz egy olyan eszközzel, mint a curl.
Mindaddig, amíg a kötési eszköz képes adatokat kötni a megfelelő névvel ellátott tulajdonságokhoz vagy argumentumokhoz, a modellkötés sikeres lesz. Az alábbi példa bemutatja, hogyan használható ByteArrayModelBinder nézetmodellekkel:
[HttpPost("Profile")]
public void SaveProfile([FromForm] ProfileViewModel model)
{
// Don't trust the file name sent by the client. Use
// Path.GetRandomFileName to generate a safe random
// file name. _targetFilePath receives a value
// from configuration (the appsettings.json file in
// the sample app).
var trustedFileName = Path.GetRandomFileName();
var filePath = Path.Combine(_targetFilePath, trustedFileName);
if (System.IO.File.Exists(filePath))
{
return;
}
System.IO.File.WriteAllBytes(filePath, model.File);
}
public class ProfileViewModel
{
public byte[] File { get; set; }
public string FileName { get; set; }
}
Egyéni modell iratgyűjtő mintája
Ebben a szakaszban egy egyéni modellkötőt implementálunk, amely a következő:
- A bejövő kérések adatait erősen beírt kulcsargumentumokká alakítja.
- Az Entity Framework Core használatával lekéri a társított entitást.
- A társított entitást argumentumként továbbítja a műveletmetódusnak.
A következő minta a ModelBinder modell attribútumát Author használja:
using CustomModelBindingSample.Binders;
using Microsoft.AspNetCore.Mvc;
namespace CustomModelBindingSample.Data
{
[ModelBinder(BinderType = typeof(AuthorEntityBinder))]
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string GitHub { get; set; }
public string Twitter { get; set; }
public string BlogUrl { get; set; }
}
}
Az előző kódban az ModelBinder attribútum határozza meg a műveletparaméterek kötéséhez IModelBinderAuthor használandó típust.
A következő AuthorEntityBinder osztály az Entity Framework Core használatával beolvassa az entitást egy adatforrásból, hogy kötést végezzen egy Author paraméterhez és egy authorId-hez.
public class AuthorEntityBinder : IModelBinder
{
private readonly AuthorContext _context;
public AuthorEntityBinder(AuthorContext context)
{
_context = context;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
if (!int.TryParse(value, out var id))
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName, "Author Id must be an integer.");
return Task.CompletedTask;
}
// Model will be null if not found, including for
// out of range id values (0, -3, etc.)
var model = _context.Authors.Find(id);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
Note
Az előző AuthorEntityBinder osztály egy egyedi modellkötő szemléltetésére szolgál. Az osztály nem egy keresési forgatókönyv ajánlott eljárásainak szemléltetésére szolgál. Kereséshez kösse össze a authorId az adatbázissal, és lekérdezi azt egy műveleti metódusban. Ez a megközelítés elkülöníti a modellkötési hibákat az esetektől NotFound .
Az alábbi kód bemutatja, hogyan használható a AuthorEntityBinder műveletmetódus:
[HttpGet("get/{author}")]
public IActionResult Get(Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
Az ModelBinder attribútum az alapértelmezett konvenciókat nem használó paraméterekre alkalmazható AuthorEntityBinder :
[HttpGet("{id}")]
public IActionResult GetById([ModelBinder(Name = "id")] Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
Ebben a példában, mivel az argumentum neve nem az alapértelmezett authorId, az attribútum használatával van megadva a ModelBinder paraméteren. A vezérlő és a műveleti módszer is egyszerűbb, mint az entitás keresése a műveletmetódusban. A szerző Entity Framework Core használatával történő lekérésének logikája a modellkötőbe kerül. Ez jelentős egyszerűsítést jelenthet, ha több módszer is kapcsolódik a Author modellhez.
Az attribútumot alkalmazhatja az ModelBinder egyes modelltulajdonságokra (például egy nézetmodellen), vagy a műveleti módszer paramétereire, hogy csak az adott típushoz vagy művelethez adjon meg egy bizonyos modellkötőt vagy modellnevet.
ModelBinderProvider implementálása
Attribútum alkalmazása helyett implementálhatja a műveletet IModelBinderProvider. Így implementálják a beépített keretrendszer-kötéseket. Amikor megadja, hogy milyen típusú kötést használ, az általa előállított argumentumtípust kell megadnia, nem pedig azt a bemenetet, amit a kötéskészítő elfogad. A következő iratgyűjtő-szolgáltató együttműködik a AuthorEntityBinder. Amikor hozzáadja az MVC szolgáltatóinak gyűjteményéhez, nem kell használnia a ModelBinder attribútumot a Author vagy Author típusú paramétereknél.
using CustomModelBindingSample.Data;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
namespace CustomModelBindingSample.Binders
{
public class AuthorEntityBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(Author))
{
return new BinderTypeModelBinder(typeof(AuthorEntityBinder));
}
return null;
}
}
}
Megjegyzés: Az előző kód egy
BinderTypeModelBinder.BinderTypeModelBindera modellkötők gyáraként működik, és függőséginjektálást (DI) biztosít. AAuthorEntityBindermegköveteli a DI-t, hogy hozzáférjen EF Core. Akkor használjaBinderTypeModelBinder, ha a modell iratgyűjtőjéhez a diától származó szolgáltatások szükségesek.
Egyéni modell iratgyűjtő szolgáltató használatához vegye fel a következőbe ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AuthorContext>(options => options.UseInMemoryDatabase("Authors"));
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0, new AuthorEntityBinderProvider());
});
}
A modellkötők kiértékelésekor a szolgáltatók gyűjteményének vizsgálata sorrendben történik. A rendszer az első olyan szolgáltatót használja, amely a bemeneti modellnek megfelelő iratgyűjtőt ad vissza. Ha a szolgáltatót hozzáadja a gyűjtemény végéhez, az azt eredményezheti, hogy a rendszer meghív egy beépített modellkötőt, mielőtt az egyéni kötőnek esélye lesz rá. Ebben a példában egy testreszabott szolgáltatót adunk hozzá a gyűjtemény elejére, hogy biztosítsuk annak használatát a műveletargumentumokhoz Author .
Polimorf modell kötése
A származtatott típusok különböző modelljeihez való kötést polimorf modellkötésnek nevezzük. Polimorfikus egyéni modellkötésre van szükség, ha a kérelem értékét az adott származtatott modelltípushoz kell kötni. Polimorf modell kötése:
- Nem jellemző az REST olyan API-kra, amelyek minden nyelvvel együttműködnek.
- Megnehezíti a kötött modellek magyarázatát.
Ha azonban egy alkalmazás polimorf modellkötést igényel, az implementáció a következő kódhoz hasonlóan nézhet ki:
public abstract class Device
{
public string Kind { get; set; }
}
public class Laptop : Device
{
public string CPUIndex { get; set; }
}
public class SmartPhone : Device
{
public string ScreenSize { get; set; }
}
public class DeviceModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType != typeof(Device))
{
return null;
}
var subclasses = new[] { typeof(Laptop), typeof(SmartPhone), };
var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
foreach (var type in subclasses)
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
}
return new DeviceModelBinder(binders);
}
}
public class DeviceModelBinder : IModelBinder
{
private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;
public DeviceModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> binders)
{
this.binders = binders;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var modelKindName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, nameof(Device.Kind));
var modelTypeValue = bindingContext.ValueProvider.GetValue(modelKindName).FirstValue;
IModelBinder modelBinder;
ModelMetadata modelMetadata;
if (modelTypeValue == "Laptop")
{
(modelMetadata, modelBinder) = binders[typeof(Laptop)];
}
else if (modelTypeValue == "SmartPhone")
{
(modelMetadata, modelBinder) = binders[typeof(SmartPhone)];
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
modelMetadata,
bindingInfo: null,
bindingContext.ModelName);
await modelBinder.BindModelAsync(newBindingContext);
bindingContext.Result = newBindingContext.Result;
if (newBindingContext.Result.IsModelSet)
{
// Setting the ValidationState ensures properties on derived types are correctly
bindingContext.ValidationState[newBindingContext.Result.Model] = new ValidationStateEntry
{
Metadata = modelMetadata,
};
}
}
}
Javaslatok és ajánlott eljárások
Egyéni modellkötők alkalmazása
- Ne próbáljon meg állapotkódokat beállítani vagy eredményeket visszaadni (például: 404 Nem található). Ha a modellkötés sikertelen, a műveletmetóduson belüli műveletszűrőnek vagy logikának kell kezelnie a hibát.
- A leghatékonyabbak az ismétlődő kód és a műveletmetszetekkel kapcsolatos keresztvágási problémák kiküszöbölésére.
- A sztringeket általában nem szabad egyéni típussá alakítani, TypeConverter ez általában jobb megoldás.
Készítette: Steve Smith
A modellkötés lehetővé teszi, hogy a vezérlőműveletek a HTTP-kérések helyett közvetlenül modelltípusokkal (metódusargumentumokként átadva) működjenek. A bejövő kérelmek adatai és az alkalmazásmodellek közötti leképezést modellkötők kezelik. A fejlesztők egyéni modellkötők implementálásával bővíthetik a beépített modellkötési funkciókat (bár általában nincs szükség arra, hogy saját szolgáltatót írjanak).
Mintakód megtekintése vagy letöltése (hogyan töltsd le)
Alapértelmezett modellkötő korlátozások
Az alapértelmezett modellkötők támogatják a legtöbb gyakori .NET Core-adattípust, és a legtöbb fejlesztő igényeit kielégítik. Azt várják, hogy a kérés szövegalapú bemenetét közvetlenül a modelltípusokhoz kötik. Előfordulhat, hogy a kötés előtt át kell alakítania a bemenetet. Ha például rendelkezik egy olyan kulccsal, amellyel modelladatokat kereshet. Saját modellkötő használatával lekérheti az adatokat a kulcs alapján.
Modellkötés áttekintése
A modellkötés meghatározott definíciókat használ az általa használt típusokhoz. Egy egyszerű típus egyetlen sztringből lesz konvertálva a bemenetben. A összetett típus több bemeneti értékből konvertálódik. A keretrendszer a különbséget TypeConverter létezése alapján határozza meg. Javasoljuk, hogy hozzon létre egy típuskonvertert, ha olyan egyszerű string leképezéssel>SomeType rendelkezik, amely nem igényel külső erőforrásokat.
Mielőtt saját egyéni modellkötőt hozna létre, érdemes áttekinteni, hogy a meglévő modellkötők hogyan vannak implementálva. ByteArrayModelBinder A base64 kódolású sztringek bájttömbökké alakításához használható. A bájttömböket gyakran fájlokként vagy adatbázis BLOB-mezőkként tárolják.
A ByteArrayModelBinder használata
A Base64 kódolású sztringek bináris adatok megjelenítésére használhatók. Egy kép például sztringként kódolható. A minta egy képet tartalmaz alap64 kódolású sztringként aBase64String.txt.
ASP.NET Core MVC képes egy base64-kódolt karakterláncot felvenni, és ByteArrayModelBinder segítségével bájttömbbé alakítani. A ByteArrayModelBinderProvider az byte[] argumentumokat a ByteArrayModelBinder-ra/-re képezi le:
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(byte[]))
{
return new ByteArrayModelBinder();
}
return null;
}
Saját egyéni modellkötés létrehozásakor implementálhatja a saját IModelBinderProvider típusát, vagy használhatja a ModelBinderAttribute.
Az alábbi példa bemutatja, hogyan lehet egy base64-kódolású stringet ByteArrayModelBinder segítségével byte[] formátummá alakítani, és az eredményt fájlba menteni.
[HttpPost]
public void Post([FromForm] byte[] file, string filename)
{
// Don't trust the file name sent by the client. Use
// Path.GetRandomFileName to generate a safe random
// file name. _targetFilePath receives a value
// from configuration (the appsettings.json file in
// the sample app).
var trustedFileName = Path.GetRandomFileName();
var filePath = Path.Combine(_targetFilePath, trustedFileName);
if (System.IO.File.Exists(filePath))
{
return;
}
System.IO.File.WriteAllBytes(filePath, file);
}
Egy base64 kódolású sztringet postázhat az előző API-metódushoz egy olyan eszközzel, mint a curl.
Mindaddig, amíg a kötési eszköz képes adatokat kötni a megfelelő névvel ellátott tulajdonságokhoz vagy argumentumokhoz, a modellkötés sikeres lesz. Az alábbi példa bemutatja, hogyan használható ByteArrayModelBinder nézetmodellekkel:
[HttpPost("Profile")]
public void SaveProfile([FromForm] ProfileViewModel model)
{
// Don't trust the file name sent by the client. Use
// Path.GetRandomFileName to generate a safe random
// file name. _targetFilePath receives a value
// from configuration (the appsettings.json file in
// the sample app).
var trustedFileName = Path.GetRandomFileName();
var filePath = Path.Combine(_targetFilePath, trustedFileName);
if (System.IO.File.Exists(filePath))
{
return;
}
System.IO.File.WriteAllBytes(filePath, model.File);
}
public class ProfileViewModel
{
public byte[] File { get; set; }
public string FileName { get; set; }
}
Egyéni modell iratgyűjtő mintája
Ebben a szakaszban egy egyéni modellkötőt implementálunk, amely a következő:
- A bejövő kérések adatait erősen beírt kulcsargumentumokká alakítja.
- Az Entity Framework Core használatával lekéri a társított entitást.
- A társított entitást argumentumként továbbítja a műveletmetódusnak.
A következő minta a ModelBinder modell attribútumát Author használja:
using CustomModelBindingSample.Binders;
using Microsoft.AspNetCore.Mvc;
namespace CustomModelBindingSample.Data
{
[ModelBinder(BinderType = typeof(AuthorEntityBinder))]
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public string GitHub { get; set; }
public string Twitter { get; set; }
public string BlogUrl { get; set; }
}
}
Az előző kódban az ModelBinder attribútum határozza meg a műveletparaméterek kötéséhez IModelBinderAuthor használandó típust.
A következő AuthorEntityBinder osztály az Entity Framework Core használatával beolvassa az entitást egy adatforrásból, hogy kötést végezzen egy Author paraméterhez és egy authorId-hez.
public class AuthorEntityBinder : IModelBinder
{
private readonly AppDbContext _db;
public AuthorEntityBinder(AppDbContext db)
{
_db = db;
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var modelName = bindingContext.ModelName;
// Try to fetch the value of the argument by name
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
{
return Task.CompletedTask;
}
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
var value = valueProviderResult.FirstValue;
// Check if the argument value is null or empty
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}
if (!int.TryParse(value, out var id))
{
// Non-integer arguments result in model state errors
bindingContext.ModelState.TryAddModelError(
modelName, "Author Id must be an integer.");
return Task.CompletedTask;
}
// Model will be null if not found, including for
// out of range id values (0, -3, etc.)
var model = _db.Authors.Find(id);
bindingContext.Result = ModelBindingResult.Success(model);
return Task.CompletedTask;
}
}
Note
Az előző AuthorEntityBinder osztály egy egyedi modellkötő szemléltetésére szolgál. Az osztály nem egy keresési forgatókönyv ajánlott eljárásainak szemléltetésére szolgál. Kereséshez kösse össze a authorId az adatbázissal, és lekérdezi azt egy műveleti metódusban. Ez a megközelítés elkülöníti a modellkötési hibákat az esetektől NotFound .
Az alábbi kód bemutatja, hogyan használható a AuthorEntityBinder műveletmetódus:
[HttpGet("get/{author}")]
public IActionResult Get(Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
Az ModelBinder attribútum az alapértelmezett konvenciókat nem használó paraméterekre alkalmazható AuthorEntityBinder :
[HttpGet("{id}")]
public IActionResult GetById([ModelBinder(Name = "id")] Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
Ebben a példában, mivel az argumentum neve nem az alapértelmezett authorId, az attribútum használatával van megadva a ModelBinder paraméteren. A vezérlő és a műveleti módszer is egyszerűbb, mint az entitás keresése a műveletmetódusban. A szerző Entity Framework Core használatával történő lekérésének logikája a modellkötőbe kerül. Ez jelentős egyszerűsítést jelenthet, ha több módszer is kapcsolódik a Author modellhez.
Az attribútumot alkalmazhatja az ModelBinder egyes modelltulajdonságokra (például egy nézetmodellen), vagy a műveleti módszer paramétereire, hogy csak az adott típushoz vagy művelethez adjon meg egy bizonyos modellkötőt vagy modellnevet.
ModelBinderProvider implementálása
Attribútum alkalmazása helyett implementálhatja a műveletet IModelBinderProvider. Így implementálják a beépített keretrendszer-kötéseket. Amikor megadja, hogy milyen típusú kötést használ, az általa előállított argumentumtípust kell megadnia, nem pedig azt a bemenetet, amit a kötéskészítő elfogad. A következő iratgyűjtő-szolgáltató együttműködik a AuthorEntityBinder. Amikor hozzáadja az MVC szolgáltatóinak gyűjteményéhez, nem kell használnia a ModelBinder attribútumot a Author vagy Author típusú paramétereknél.
using CustomModelBindingSample.Data;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System;
namespace CustomModelBindingSample.Binders
{
public class AuthorEntityBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(Author))
{
return new BinderTypeModelBinder(typeof(AuthorEntityBinder));
}
return null;
}
}
}
Megjegyzés: Az előző kód egy
BinderTypeModelBinder.BinderTypeModelBindera modellkötők gyáraként működik, és függőséginjektálást (DI) biztosít. AAuthorEntityBindermegköveteli a DI-t, hogy hozzáférjen EF Core. Akkor használjaBinderTypeModelBinder, ha a modell iratgyűjtőjéhez a diától származó szolgáltatások szükségesek.
Egyéni modell iratgyűjtő szolgáltató használatához vegye fel a következőbe ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase("App"));
services.AddMvc(options =>
{
// add custom binder to beginning of collection
options.ModelBinderProviders.Insert(0, new AuthorEntityBinderProvider());
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
A modellkötők kiértékelésekor a szolgáltatók gyűjteményének vizsgálata sorrendben történik. A rendszer az első olyan szolgáltatót használja, amely egy kötőanyagot ad vissza. Ha a szolgáltatót hozzáadja a gyűjtemény végéhez, a rendszer meghívhat egy beépített modell-iratgyűjtőt, mielőtt az egyéni iratgyűjtőnek esélye lesz rá. Ebben a példában az egyéni szolgáltatót a gyűjtemény elejére adjuk hozzá, hogy biztosítsuk annak használatát a Author műveletargumentumokhoz.
Polimorf modell kötése
A származtatott típusok különböző modelljeihez való kötést polimorf modellkötésnek nevezzük. Polimorfikus egyéni modellkötésre van szükség, ha a kérelem értékét az adott származtatott modelltípushoz kell kötni. Polimorf modell kötése:
- Nem jellemző az REST olyan API-kra, amelyek minden nyelvvel együttműködnek.
- Megnehezíti a kötött modellek magyarázatát.
Ha azonban egy alkalmazás polimorf modellkötést igényel, az implementáció a következő kódhoz hasonlóan nézhet ki:
public abstract class Device
{
public string Kind { get; set; }
}
public class Laptop : Device
{
public string CPUIndex { get; set; }
}
public class SmartPhone : Device
{
public string ScreenSize { get; set; }
}
public class DeviceModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType != typeof(Device))
{
return null;
}
var subclasses = new[] { typeof(Laptop), typeof(SmartPhone), };
var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
foreach (var type in subclasses)
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
}
return new DeviceModelBinder(binders);
}
}
public class DeviceModelBinder : IModelBinder
{
private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;
public DeviceModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> binders)
{
this.binders = binders;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
var modelKindName = ModelNames.CreatePropertyModelName(bindingContext.ModelName, nameof(Device.Kind));
var modelTypeValue = bindingContext.ValueProvider.GetValue(modelKindName).FirstValue;
IModelBinder modelBinder;
ModelMetadata modelMetadata;
if (modelTypeValue == "Laptop")
{
(modelMetadata, modelBinder) = binders[typeof(Laptop)];
}
else if (modelTypeValue == "SmartPhone")
{
(modelMetadata, modelBinder) = binders[typeof(SmartPhone)];
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
modelMetadata,
bindingInfo: null,
bindingContext.ModelName);
await modelBinder.BindModelAsync(newBindingContext);
bindingContext.Result = newBindingContext.Result;
if (newBindingContext.Result.IsModelSet)
{
// Setting the ValidationState ensures properties on derived types are correctly
bindingContext.ValidationState[newBindingContext.Result.Model] = new ValidationStateEntry
{
Metadata = modelMetadata,
};
}
}
}
Javaslatok és ajánlott eljárások
Egyéni modellkötők alkalmazása
- Ne próbáljon meg állapotkódokat beállítani vagy eredményeket visszaadni (például: 404 Nem található). Ha a modellkötés sikertelen, a műveletmetóduson belüli műveletszűrőnek vagy logikának kell kezelnie a hibát.
- A leghatékonyabbak az ismétlődő kód és a műveletmetszetekkel kapcsolatos keresztvágási problémák kiküszöbölésére.
- A sztringeket általában nem szabad egyéni típussá alakítani, TypeConverter ez általában jobb megoldás.