Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Tarafından Kirk Larkin
Model bağlama, denetleyici eylemlerinin HTTP istekleri yerine model türleriyle (yöntem bağımsız değişkenleri olarak geçirilir) doğrudan çalışmasını sağlar. Gelen istek verileri ve uygulama modelleri arasındaki eşleme, model bağlayıcıları tarafından işlenir. Geliştiriciler, özel model bağlayıcıları uygulayarak yerleşik model bağlama işlevselliğini genişletebilir (ancak genellikle kendi sağlayıcınızı yazmanız gerekmez).
Örnek kodu görüntüleme veya indirme (indirme)
Varsayılan model bağlayıcı sınırlamaları
Varsayılan model bağlayıcıları yaygın .NET Core veri türlerinin çoğunu destekler ve çoğu geliştiricinin gereksinimlerini karşılamalıdır. İstekten gelen metin tabanlı girişi doğrudan model türlerine bağlamayı beklerler. Bağlamadan önce girişi dönüştürmeniz gerekebilir. Örneğin, model verilerini aramak için kullanılabilecek bir anahtarınız olduğunda. Anahtara göre veri almak için özel model bağlayıcı kullanabilirsiniz.
Model bağlama basit ve karmaşık türler
Model bağlama, üzerinde çalıştığı türler için belirli tanımları kullanır.
Basit bir tür, TypeConverter veya TryParse yöntemi kullanılarak tek bir dizeden dönüştürülür. Bir karmaşık tür, birden fazla giriş değerinden dönüştürülür. Çerçeve, TypeConverter veya TryParse varlığının olup olmadığına göre farkı belirler. Bir tür dönüştürücüsü oluşturmanızı veya harici kaynaklar ya da birden fazla giriş gerektirmeyen bir TryParse'den string'a dönüşüm için SomeType kullanmanızı öneririz.
Model bağlayıcısının dizelerden dönüştürebileceği türlerin listesi için bkz. Basit türler.
Kendi özel model bağlayıcınızı oluşturmadan önce, mevcut model bağlayıcılarının nasıl uygulandığını gözden geçirmeye değer. ByteArrayModelBinder Base64 ile kodlanmış dizeleri bayt dizilerine dönüştürmek için hangilerinin kullanılabileceğini düşünün. Bayt dizileri genellikle dosya veya veritabanı BLOB alanları olarak depolanır.
ByteArrayModelBinder ile çalışma
İkili verileri temsil etmek için Base64 ile kodlanmış dizeler kullanılabilir. Örneğin, bir görüntü dize olarak kodlanabilir. Örnek, Base64String.txtiçinde base64 kodlu dize olarak bir görüntü içerir.
ASP.NET Core MVC, base64 ile kodlanmış bir dize alabilir ve bunu bayt dizisine dönüştürmek için bir ByteArrayModelBinder kullanabilir.
ByteArrayModelBinderProvider bağımsız değişkenleri byte[]'i ByteArrayModelBinder ile eşler.
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;
}
Kendi özel model bağlayıcınızı oluştururken, kendi IModelBinderProvider türünüzü uygulayabilir veya kullanabilirsiniz ModelBinderAttribute.
Aşağıdaki örnek, base64 ile kodlanmış bir dizeyi ByteArrayModelBinder'ye dönüştürmek ve sonucu bir dosyaya kaydetmek için byte[]'in nasıl kullanılacağını göstermektedir:
[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);
}
Kod açıklamalarının İngilizce dışındaki dillere çevirisini görmek isterseniz, bunu bu GitHub tartışma konusunda bize bildirin.
Curl gibi bir araç kullanarak base64 ile kodlanmış bir dizeyi önceki api yöntemine GÖNDERebilirsiniz.
Bağlayıcı, istek verilerini uygun şekilde adlandırılmış özelliklere veya bağımsız değişkenlere bağlayabildiği sürece model bağlama başarılı olur. Aşağıdaki örnek, ByteArrayModelBinder'un bir görünüm modeliyle nasıl kullanılacağını göstermektedir.
[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; }
}
Özel model bağlayıcı örneği
Bu bölümde şunları sağlayan özel bir model bağlayıcısı uygulayacağız:
- Gelen istek verilerini kesin olarak belirlenmiş anahtar bağımsız değişkenlerine dönüştürür.
- İlişkili varlığı getirmek için Entity Framework Core kullanır.
- İlişkili varlığı metot fonksiyonuna bağımsız değişken olarak geçirir.
Aşağıdaki örnek, ModelBinder özniteliğini Author modelinde kullanır:
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; }
}
}
Önceki kodda, ModelBinder özniteliği, IModelBinder eylem parametrelerini bağlamak için kullanılacak Author türünü belirtir.
Aşağıdaki AuthorEntityBinder sınıf, Entity Framework Core ve Author kullanarak bir veri kaynağından varlık getirip, authorId parametresini bağlar.
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
Önceki AuthorEntityBinder sınıf, özel model bağlayıcısını göstermek için tasarlanmıştır. Sınıf, bir arama senaryosu için en iyi uygulamaları göstermek üzere tasarlanmamıştır. Bağlantı kurmak için authorId kullanın ve veritabanını bir eylem yöntemiyle sorgulayın. Bu yaklaşım model bağlama hatalarını NotFound durumlarından ayırır.
Aşağıdaki kod, bir eylem yönteminde öğesinin AuthorEntityBinder nasıl kullanılacağını gösterir:
[HttpGet("get/{author}")]
public IActionResult Get(Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
ModelBinder özniteliği, AuthorEntityBinder'yi varsayılan kuralları kullanmayan parametrelere uygulamak için kullanılabilir.
[HttpGet("{id}")]
public IActionResult GetById([ModelBinder(Name = "id")] Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
Bu örnekte, bağımsız değişkenin adı varsayılan authorIdolmadığından özniteliği kullanılarak ModelBinder parametresinde belirtilir. Eylem yönteminde varlığı aramaya kıyasla hem denetleyici hem de eylem yöntemi basitleştirilmiştir. Entity Framework Core kullanarak yazarı getirme mantığı model bağlayıcısına aktarıldı. Modele bağlanan Author birkaç yönteminiz olduğunda bu önemli bir basitleştirme olabilir.
Özniteliği tek tek model özelliklerine (görünüm modelinde olduğu gibi) veya eylem yöntemi parametrelerine uygulayarak ModelBinder yalnızca bu tür veya eylem için belirli bir model bağlayıcısı veya model adı belirtebilirsiniz.
ModelBinderProvider Uygulaması Gerçekleştirme
Özniteliği uygulamak yerine uygulayabilirsiniz IModelBinderProvider. Yerleşik çerçeve bağlayıcıları bu şekilde uygulanır. Bağlayıcınızın üzerinde çalıştığı türü belirttiğinizde, bağlayıcınızın kabul ettiği girdi değil, ürettiği bağımsız değişkenin türünü belirtirsiniz. Aşağıdaki bağlayıcı sağlayıcısı şu AuthorEntityBinder ile çalışır. MVC'nin sağlayıcı koleksiyonuna eklendiğinde, ModelBinder veya Author türündeki parametrelerde Author özniteliğini kullanmanız gerekmez.
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;
}
}
}
Not: Yukarıdaki kod bir
BinderTypeModelBinderdöndürür.BinderTypeModelBindermodel bağlayıcıları için fabrika görevi görür ve bağımlılık ekleme (DI) sağlar.AuthorEntityBinderiçin DI'nin EF Core erişmesi gerekir. Model bağlayıcınızın DI hizmetlerinden yararlanması gerekiyorsaBinderTypeModelBinderkullanın.
Özel model bağlayıcı sağlayıcısını kullanmak için ConfigureServices şuraya ekleyin:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AuthorContext>(options => options.UseInMemoryDatabase("Authors"));
services.AddControllers(options =>
{
options.ModelBinderProviders.Insert(0, new AuthorEntityBinderProvider());
});
}
Model bağlayıcıları değerlendirilirken sağlayıcı koleksiyonu sırayla inceleniyor. Giriş modeliyle eşleşen bir bağlayıcı döndüren ilk sağlayıcı kullanılır. Sağlayıcınızı koleksiyonun sonuna eklemek, özel bağlayıcınızın çalışmasına fırsat kalmadan önce yerleşik bir model bağlayıcısının çağrılmasıyla sonuçlanabilir. Bu örnekte, özel sağlayıcı her zaman işlem bağımsız değişkenleri için kullanıldığından emin olmak amacıyla Author koleksiyonun başına eklenir.
Polimorfik model bağlama
Türetilmiş türlerin farklı modellerine bağlama, polimorfik model bağlama olarak bilinir. İstek değerinin belirli türetilmiş model türüne bağlanması gerektiğinde çok biçimli özelleştirilmiş model bağlama gerekir. Polimorfik model bağlama:
- Tüm dillerle birlikte çalışabilecek şekilde tasarlanmış bir REST API için tipik değildir.
- İlişkili modeller hakkında mantık yürütmeyi zorlaştırır.
Ancak, bir uygulama çok biçimli model bağlaması gerektiriyorsa, bir uygulama aşağıdaki kod gibi görünebilir:
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,
};
}
}
}
Öneriler ve en iyi yöntemler
Özel model bağlayıcıları:
- Durum kodlarını ayarlamaya veya sonuçları döndürmeye çalışmamalıdır (örneğin, 404 Bulunamadı). Model bağlama başarısız olursa, eylem yönteminin içindeki bir eylem filtresi veya mantık hatayı işlemelidir.
- Tekrarlanan kodları ve aksiyon metotlarından genel kaygıları ortadan kaldırmak için en kullanışlı olanlardır.
- Genellikle bir dizeyi özel bir türe dönüştürmek için kullanılmamalıdır; TypeConverter genellikle daha iyi bir seçenektir.
Tarafından Steve Smith
Model bağlama, denetleyici eylemlerinin HTTP istekleri yerine model türleriyle (yöntem bağımsız değişkenleri olarak geçirilir) doğrudan çalışmasını sağlar. Gelen istek verileri ve uygulama modelleri arasındaki eşleme, model bağlayıcıları tarafından işlenir. Geliştiriciler, özel model bağlayıcıları uygulayarak yerleşik model bağlama işlevselliğini genişletebilir (ancak genellikle kendi sağlayıcınızı yazmanız gerekmez).
Örnek kodu görüntüleme veya indirme (indirme)
Varsayılan model bağlayıcı sınırlamaları
Varsayılan model bağlayıcıları yaygın .NET Core veri türlerinin çoğunu destekler ve çoğu geliştiricinin gereksinimlerini karşılamalıdır. İstekten gelen metin tabanlı girişi doğrudan model türlerine bağlamayı beklerler. Bağlamadan önce girişi dönüştürmeniz gerekebilir. Örneğin, model verilerini aramak için kullanılabilecek bir anahtarınız olduğunda. Anahtara göre veri almak için özel model bağlayıcı kullanabilirsiniz.
Model bağlama incelemesi
Model bağlama, üzerinde çalıştığı türler için belirli tanımları kullanır.
Basit bir tür, girişteki tek bir dizeden dönüştürülür. Bir karmaşık tür, birden fazla giriş değerinden dönüştürülür. Çerçeve, bir TypeConvertervarlığını temel alarak farkı belirler. Dış kaynak gerektirmeyen basit string>SomeType bir eşlemeniz varsa bir tür dönüştürücü oluşturmanızı öneririz.
Kendi özel model bağlayıcınızı oluşturmadan önce, mevcut model bağlayıcılarının nasıl uygulandığını gözden geçirmeye değer. ByteArrayModelBinder Base64 ile kodlanmış dizeleri bayt dizilerine dönüştürmek için hangilerinin kullanılabileceğini düşünün. Bayt dizileri genellikle dosya veya veritabanı BLOB alanları olarak depolanır.
ByteArrayModelBinder ile çalışma
İkili verileri temsil etmek için Base64 ile kodlanmış dizeler kullanılabilir. Örneğin, bir görüntü dize olarak kodlanabilir. Örnek, Base64String.txtiçinde base64 kodlu dize olarak bir görüntü içerir.
ASP.NET Core MVC, base64 ile kodlanmış bir dize alabilir ve bunu bayt dizisine dönüştürmek için bir ByteArrayModelBinder kullanabilir.
ByteArrayModelBinderProvider bağımsız değişkenleri byte[]'i ByteArrayModelBinder ile eşler.
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(byte[]))
{
return new ByteArrayModelBinder();
}
return null;
}
Kendi özel model bağlayıcınızı oluştururken, kendi IModelBinderProvider türünüzü uygulayabilir veya kullanabilirsiniz ModelBinderAttribute.
Aşağıdaki örnek, base64 ile kodlanmış bir dizeyi ByteArrayModelBinder'ye dönüştürmek ve sonucu bir dosyaya kaydetmek için byte[]'in nasıl kullanılacağını göstermektedir:
[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);
}
Curl gibi bir araç kullanarak base64 ile kodlanmış bir dizeyi önceki api yöntemine GÖNDERebilirsiniz.
Bağlayıcı, istek verilerini uygun şekilde adlandırılmış özelliklere veya bağımsız değişkenlere bağlayabildiği sürece model bağlama başarılı olur. Aşağıdaki örnek, ByteArrayModelBinder'un bir görünüm modeliyle nasıl kullanılacağını göstermektedir.
[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; }
}
Özel model bağlayıcı örneği
Bu bölümde şunları sağlayan özel bir model bağlayıcısı uygulayacağız:
- Gelen istek verilerini kesin olarak belirlenmiş anahtar bağımsız değişkenlerine dönüştürür.
- İlişkili varlığı getirmek için Entity Framework Core kullanır.
- İlişkili varlığı metot fonksiyonuna bağımsız değişken olarak geçirir.
Aşağıdaki örnek, ModelBinder özniteliğini Author modelinde kullanır:
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; }
}
}
Önceki kodda, ModelBinder özniteliği, IModelBinder eylem parametrelerini bağlamak için kullanılacak Author türünü belirtir.
Aşağıdaki AuthorEntityBinder sınıf, Entity Framework Core ve Author kullanarak bir veri kaynağından varlık getirip, authorId parametresini bağlar.
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
Önceki AuthorEntityBinder sınıf, özel model bağlayıcısını göstermek için tasarlanmıştır. Sınıf, bir arama senaryosu için en iyi uygulamaları göstermek üzere tasarlanmamıştır. Bağlantı kurmak için authorId kullanın ve veritabanını bir eylem yöntemiyle sorgulayın. Bu yaklaşım model bağlama hatalarını NotFound durumlarından ayırır.
Aşağıdaki kod, bir eylem yönteminde öğesinin AuthorEntityBinder nasıl kullanılacağını gösterir:
[HttpGet("get/{author}")]
public IActionResult Get(Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
ModelBinder özniteliği, AuthorEntityBinder'yi varsayılan kuralları kullanmayan parametrelere uygulamak için kullanılabilir.
[HttpGet("{id}")]
public IActionResult GetById([ModelBinder(Name = "id")] Author author)
{
if (author == null)
{
return NotFound();
}
return Ok(author);
}
Bu örnekte, bağımsız değişkenin adı varsayılan authorIdolmadığından özniteliği kullanılarak ModelBinder parametresinde belirtilir. Eylem yönteminde varlığı aramaya kıyasla hem denetleyici hem de eylem yöntemi basitleştirilmiştir. Entity Framework Core kullanarak yazarı getirme mantığı model bağlayıcısına aktarıldı. Modele bağlanan Author birkaç yönteminiz olduğunda bu önemli bir basitleştirme olabilir.
Özniteliği tek tek model özelliklerine (görünüm modelinde olduğu gibi) veya eylem yöntemi parametrelerine uygulayarak ModelBinder yalnızca bu tür veya eylem için belirli bir model bağlayıcısı veya model adı belirtebilirsiniz.
ModelBinderProvider Uygulaması Gerçekleştirme
Özniteliği uygulamak yerine uygulayabilirsiniz IModelBinderProvider. Yerleşik çerçeve bağlayıcıları bu şekilde uygulanır. Bağlayıcınızın üzerinde çalıştığı türü belirttiğinizde, bağlayıcınızın kabul ettiği girdi değil, ürettiği bağımsız değişkenin türünü belirtirsiniz. Aşağıdaki bağlayıcı sağlayıcısı şu AuthorEntityBinder ile çalışır. MVC'nin sağlayıcı koleksiyonuna eklendiğinde, ModelBinder veya Author türündeki parametrelerde Author özniteliğini kullanmanız gerekmez.
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;
}
}
}
Not: Yukarıdaki kod bir
BinderTypeModelBinderdöndürür.BinderTypeModelBindermodel bağlayıcıları için fabrika görevi görür ve bağımlılık ekleme (DI) sağlar.AuthorEntityBinderiçin DI'nin EF Core erişmesi gerekir. Model bağlayıcınızın DI hizmetlerinden yararlanması gerekiyorsaBinderTypeModelBinderkullanın.
Özel model bağlayıcı sağlayıcısını kullanmak için ConfigureServices şuraya ekleyin:
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);
}
Model bağlayıcıları değerlendirilirken sağlayıcı koleksiyonu sırayla inceleniyor. Bağlayıcı döndüren ilk sağlayıcı kullanılır. Sağlayıcınızı koleksiyonun sonuna eklemek, özel bağlayıcınızı kullanma fırsatını bulamadan önce yerleşik model bağlayıcısının çağrılmasıyla sonuçlanabilir. Bu örnekte, özel sağlayıcının eylem bağımsız değişkenleri için kullanılmasını sağlamak adına Author koleksiyonun başına eklenir.
Polimorfik model bağlama
Türetilmiş türlerin farklı modellerine bağlama, polimorfik model bağlama olarak bilinir. İstek değerinin belirli türetilmiş model türüne bağlanması gerektiğinde çok biçimli özelleştirilmiş model bağlama gerekir. Polimorfik model bağlama:
- Tüm dillerle birlikte çalışabilecek şekilde tasarlanmış bir REST API için tipik değildir.
- İlişkili modeller hakkında mantık yürütmeyi zorlaştırır.
Ancak, bir uygulama çok biçimli model bağlaması gerektiriyorsa, bir uygulama aşağıdaki kod gibi görünebilir:
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,
};
}
}
}
Öneriler ve en iyi yöntemler
Özel model bağlayıcıları:
- Durum kodlarını ayarlamaya veya sonuçları döndürmeye çalışmamalıdır (örneğin, 404 Bulunamadı). Model bağlama başarısız olursa, eylem yönteminin içindeki bir eylem filtresi veya mantık hatayı işlemelidir.
- Tekrarlanan kodları ve aksiyon metotlarından genel kaygıları ortadan kaldırmak için en kullanışlı olanlardır.
- Genellikle bir dizeyi özel bir türe dönüştürmek için kullanılmamalıdır; TypeConverter genellikle daha iyi bir seçenektir.
ASP.NET Core