ASP.NET Core Web API'sindeki özel biçimlendiriciler
ASP.NET Core MVC, giriş ve çıkış biçimlendiricileri kullanarak Web API'lerinde veri alışverişini destekler. Giriş biçimlendiricileri Model Bağlama tarafından kullanılır. Çıkış biçimlendiricileri yanıtları biçimlendirmek için kullanılır.
Çerçeve, JSON ve XML için yerleşik giriş ve çıkış biçimlendiricileri sağlar. Düz metin için yerleşik bir çıkış biçimlendirici sağlar, ancak düz metin için giriş biçimlendiricisi sağlamaz.
Bu makalede, özel biçimlendiriciler oluşturarak ek biçimler için nasıl destek ekleneceği gösterilmektedir. Özel bir düz metin giriş biçimlendirici örneği için bkz . GitHub'da TextPlainInputFormatter .
Örnek kodu görüntüleme veya indirme (indirme)
Özel biçimlendirici ne zaman kullanılır?
Yerleşik biçimlendiriciler tarafından işlenmemiş bir içerik türü için destek eklemek için özel bir biçimlendirici kullanın.
Özel biçimlendirici oluşturmaya genel bakış
Özel biçimlendirici oluşturmak için:
- İstemciye gönderilen verileri seri hale getirmek için bir çıkış biçimlendirici sınıfı oluşturun.
- İstemciden alınan verileri seri durumdan çıkarmak için bir giriş biçimlendirici sınıfı oluşturun.
- içindeki ve OutputFormatters koleksiyonlarına MvcOptionsbiçimlendirici sınıflarının InputFormatters örneklerini ekleyin.
Özel biçimlendirici oluşturma
Biçimlendirici oluşturmak için:
- sınıfını uygun temel sınıftan türetin. Örnek uygulama ve TextInputFormatter'den TextOutputFormatter türetilir.
- Oluşturucuda desteklenen medya türlerini ve kodlamalarını belirtin.
- CanReadType ve CanWriteType yöntemlerini geçersiz kılın.
- ReadRequestBodyAsync ve WriteResponseBodyAsync yöntemlerini geçersiz kılın.
Aşağıdaki kod, örnekteki VcardOutputFormatter
sınıfı gösterir:
public class VcardOutputFormatter : TextOutputFormatter
{
public VcardOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
protected override bool CanWriteType(Type? type)
=> typeof(Contact).IsAssignableFrom(type)
|| typeof(IEnumerable<Contact>).IsAssignableFrom(type);
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var httpContext = context.HttpContext;
var serviceProvider = httpContext.RequestServices;
var logger = serviceProvider.GetRequiredService<ILogger<VcardOutputFormatter>>();
var buffer = new StringBuilder();
if (context.Object is IEnumerable<Contact> contacts)
{
foreach (var contact in contacts)
{
FormatVcard(buffer, contact, logger);
}
}
else
{
FormatVcard(buffer, (Contact)context.Object!, logger);
}
await httpContext.Response.WriteAsync(buffer.ToString(), selectedEncoding);
}
private static void FormatVcard(
StringBuilder buffer, Contact contact, ILogger logger)
{
buffer.AppendLine("BEGIN:VCARD");
buffer.AppendLine("VERSION:2.1");
buffer.AppendLine($"N:{contact.LastName};{contact.FirstName}");
buffer.AppendLine($"FN:{contact.FirstName} {contact.LastName}");
buffer.AppendLine($"UID:{contact.Id}");
buffer.AppendLine("END:VCARD");
logger.LogInformation("Writing {FirstName} {LastName}",
contact.FirstName, contact.LastName);
}
}
Uygun temel sınıftan türet
Metin medyası türleri için (örneğin, vCard), veya TextOutputFormatter temel sınıfından TextInputFormatter türet:
public class VcardOutputFormatter : TextOutputFormatter
İkili türler için veya OutputFormatter temel sınıfından InputFormatter türetilir.
Desteklenen medya türlerini ve kodlamalarını belirtme
Oluşturucuda ve koleksiyonlarına ekleyerek SupportedMediaTypes desteklenen medya türlerini ve SupportedEncodings kodlamalarını belirtin:
public VcardOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
Biçimlendirici sınıfı, bağımlılıkları için oluşturucu ekleme özelliğini kullanamaz. Örneğin, ILogger<VcardOutputFormatter>
oluşturucuya parametre olarak eklenemez. Hizmetlere erişmek için yöntemlere geçirilen bağlam nesnesini kullanın. Bu makaledeki bir kod örneği ve örnek bunun nasıl yapılacağını gösterir.
CanReadType ve CanWriteType'ı Geçersiz Kılma
veya yöntemlerini geçersiz kılarak CanReadType CanWriteType içinde seri durumdan çıkarmak veya serileştirmek için türünü belirtin. Örneğin, bir Contact
türden vCard metni oluşturmak için (veya tam tersi):
protected override bool CanWriteType(Type? type)
=> typeof(Contact).IsAssignableFrom(type)
|| typeof(IEnumerable<Contact>).IsAssignableFrom(type);
CanWriteResult yöntemi
Bazı senaryolarda yerine CanWriteResult geçersiz kılınmalıdır CanWriteType. Aşağıdaki koşullar doğruysa kullanın CanWriteResult
:
- Eylem yöntemi bir model sınıfı döndürür.
- Çalışma zamanında döndürülebilecek türetilmiş sınıflar vardır.
- Eylem tarafından döndürülen türetilmiş sınıfın çalışma zamanında bilinmesi gerekir.
Örneğin, eylem yöntemini varsayalım:
- İmza bir
Person
tür döndürür. - türünden
Person
türetilen birStudent
veyaInstructor
türü döndürebilir.
Biçimlendiricinin yalnızca Student
nesneleri işlemesi için yöntemine CanWriteResult
sağlanan bağlam nesnesindeki türünü Object denetleyin. Eylem yöntemi döndürdüğünde IActionResult:
- kullanmak
CanWriteResult
gerekli değildir. - yöntemi çalışma
CanWriteType
zamanı türünü alır.
ReadRequestBodyAsync ve WriteResponseBodyAsync'i geçersiz kılma
Seri durumdan çıkarma veya serileştirme veya veya WriteResponseBodyAsynciçinde ReadRequestBodyAsync gerçekleştirilir. Aşağıdaki örnekte, bağımlılık ekleme kapsayıcısından hizmetlerin nasıl alınacakları gösterilmektedir. Hizmetler oluşturucu parametrelerinden alınamaz:
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var httpContext = context.HttpContext;
var serviceProvider = httpContext.RequestServices;
var logger = serviceProvider.GetRequiredService<ILogger<VcardOutputFormatter>>();
var buffer = new StringBuilder();
if (context.Object is IEnumerable<Contact> contacts)
{
foreach (var contact in contacts)
{
FormatVcard(buffer, contact, logger);
}
}
else
{
FormatVcard(buffer, (Contact)context.Object!, logger);
}
await httpContext.Response.WriteAsync(buffer.ToString(), selectedEncoding);
}
private static void FormatVcard(
StringBuilder buffer, Contact contact, ILogger logger)
{
buffer.AppendLine("BEGIN:VCARD");
buffer.AppendLine("VERSION:2.1");
buffer.AppendLine($"N:{contact.LastName};{contact.FirstName}");
buffer.AppendLine($"FN:{contact.FirstName} {contact.LastName}");
buffer.AppendLine($"UID:{contact.Id}");
buffer.AppendLine("END:VCARD");
logger.LogInformation("Writing {FirstName} {LastName}",
contact.FirstName, contact.LastName);
}
MVC'yi özel biçimlendirici kullanacak şekilde yapılandırma
Özel bir biçimlendirici kullanmak için veya MvcOptions.OutputFormatters koleksiyonuna biçimlendirici sınıfının bir örneğini MvcOptions.InputFormatters ekleyin:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
});
Biçimlendiriciler, ilkinin öncelikli olduğu eklenme sırasına göre değerlendirilir.
Tam VcardInputFormatter
sınıf
Aşağıdaki kod, örnekteki VcardInputFormatter
sınıfı gösterir:
public class VcardInputFormatter : TextInputFormatter
{
public VcardInputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
protected override bool CanReadType(Type type)
=> type == typeof(Contact);
public override async Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context, Encoding effectiveEncoding)
{
var httpContext = context.HttpContext;
var serviceProvider = httpContext.RequestServices;
var logger = serviceProvider.GetRequiredService<ILogger<VcardInputFormatter>>();
using var reader = new StreamReader(httpContext.Request.Body, effectiveEncoding);
string? nameLine = null;
try
{
await ReadLineAsync("BEGIN:VCARD", reader, context, logger);
await ReadLineAsync("VERSION:", reader, context, logger);
nameLine = await ReadLineAsync("N:", reader, context, logger);
var split = nameLine.Split(";".ToCharArray());
var contact = new Contact(FirstName: split[1], LastName: split[0].Substring(2));
await ReadLineAsync("FN:", reader, context, logger);
await ReadLineAsync("END:VCARD", reader, context, logger);
logger.LogInformation("nameLine = {nameLine}", nameLine);
return await InputFormatterResult.SuccessAsync(contact);
}
catch
{
logger.LogError("Read failed: nameLine = {nameLine}", nameLine);
return await InputFormatterResult.FailureAsync();
}
}
private static async Task<string> ReadLineAsync(
string expectedText, StreamReader reader, InputFormatterContext context,
ILogger logger)
{
var line = await reader.ReadLineAsync();
if (line is null || !line.StartsWith(expectedText))
{
var errorMessage = $"Looked for '{expectedText}' and got '{line}'";
context.ModelState.TryAddModelError(context.ModelName, errorMessage);
logger.LogError(errorMessage);
throw new Exception(errorMessage);
}
return line;
}
}
Uygulamayı test etme
Temel vCard giriş ve çıkış biçimlendiricilerini uygulayan bu makale için örnek uygulamayı çalıştırın. Uygulama, vCard'ları aşağıdaki biçime benzer şekilde okur ve yazar:
BEGIN:VCARD
VERSION:2.1
N:Davolio;Nancy
FN:Nancy Davolio
END:VCARD
vCard çıkışını görmek için uygulamayı çalıştırın ve accept üst bilgisini text/vcard
https://localhost:<port>/api/contacts
içeren bir Get isteği gönderin.
Kişilerden oluşan bellek içi koleksiyona vCard eklemek için:
Post
http-repl gibi bir araçla adresine/api/contacts
istek gönderin.Content-Type
Üst bilgiyi olaraktext/vcard
ayarlayın.- Gövdedeki metni önceki örnekte olduğu gibi biçimlendirilmiş olarak ayarlayın
vCard
.
Ek kaynaklar
ASP.NET Core MVC, giriş ve çıkış biçimlendiricileri kullanarak Web API'lerinde veri alışverişini destekler. Giriş biçimlendiricileri Model Bağlama tarafından kullanılır. Çıkış biçimlendiricileri yanıtları biçimlendirmek için kullanılır.
Çerçeve, JSON ve XML için yerleşik giriş ve çıkış biçimlendiricileri sağlar. Düz metin için yerleşik bir çıkış biçimlendirici sağlar, ancak düz metin için giriş biçimlendiricisi sağlamaz.
Bu makalede, özel biçimlendiriciler oluşturarak ek biçimler için nasıl destek ekleneceği gösterilmektedir. Özel bir düz metin giriş biçimlendirici örneği için bkz . GitHub'da TextPlainInputFormatter .
Örnek kodu görüntüleme veya indirme (indirme)
Özel biçimlendirici ne zaman kullanılır?
Yerleşik biçimlendiriciler tarafından işlenmemiş bir içerik türü için destek eklemek için özel bir biçimlendirici kullanın.
Özel biçimlendirici oluşturmaya genel bakış
Özel biçimlendirici oluşturmak için:
- İstemciye gönderilen verileri seri hale getirmek için bir çıkış biçimlendirici sınıfı oluşturun.
- İstemciden alınan verileri seri durumdan çıkarmak için bir giriş biçimlendirici sınıfı oluşturun.
- içindeki ve OutputFormatters koleksiyonlarına MvcOptionsbiçimlendirici sınıflarının InputFormatters örneklerini ekleyin.
Özel biçimlendirici oluşturma
Biçimlendirici oluşturmak için:
- sınıfını uygun temel sınıftan türetin. Örnek uygulama ve TextInputFormatter'den TextOutputFormatter türetilir.
- Oluşturucuda desteklenen medya türlerini ve kodlamalarını belirtin.
- CanReadType ve CanWriteType yöntemlerini geçersiz kılın.
- ReadRequestBodyAsync ve WriteResponseBodyAsync yöntemlerini geçersiz kılın.
Aşağıdaki kod, örnekteki VcardOutputFormatter
sınıfı gösterir:
public class VcardOutputFormatter : TextOutputFormatter
{
public VcardOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
protected override bool CanWriteType(Type type)
{
return typeof(Contact).IsAssignableFrom(type) ||
typeof(IEnumerable<Contact>).IsAssignableFrom(type);
}
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var httpContext = context.HttpContext;
var serviceProvider = httpContext.RequestServices;
var logger = serviceProvider.GetRequiredService<ILogger<VcardOutputFormatter>>();
var buffer = new StringBuilder();
if (context.Object is IEnumerable<Contact> contacts)
{
foreach (var contact in contacts)
{
FormatVcard(buffer, contact, logger);
}
}
else
{
FormatVcard(buffer, (Contact)context.Object, logger);
}
await httpContext.Response.WriteAsync(buffer.ToString(), selectedEncoding);
}
private static void FormatVcard(
StringBuilder buffer, Contact contact, ILogger logger)
{
buffer.AppendLine("BEGIN:VCARD");
buffer.AppendLine("VERSION:2.1");
buffer.AppendLine($"N:{contact.LastName};{contact.FirstName}");
buffer.AppendLine($"FN:{contact.FirstName} {contact.LastName}");
buffer.AppendLine($"UID:{contact.Id}");
buffer.AppendLine("END:VCARD");
logger.LogInformation("Writing {FirstName} {LastName}",
contact.FirstName, contact.LastName);
}
}
Uygun temel sınıftan türet
Metin medyası türleri için (örneğin, vCard), veya TextOutputFormatter temel sınıfından TextInputFormatter türet:
public class VcardOutputFormatter : TextOutputFormatter
İkili türler için veya OutputFormatter temel sınıfından InputFormatter türetilir.
Desteklenen medya türlerini ve kodlamalarını belirtme
Oluşturucuda ve koleksiyonlarına ekleyerek SupportedMediaTypes desteklenen medya türlerini ve SupportedEncodings kodlamalarını belirtin:
public VcardOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
Biçimlendirici sınıfı, bağımlılıkları için oluşturucu ekleme özelliğini kullanamaz. Örneğin, ILogger<VcardOutputFormatter>
oluşturucuya parametre olarak eklenemez. Hizmetlere erişmek için yöntemlere geçirilen bağlam nesnesini kullanın. Bu makaledeki bir kod örneği ve örnek bunun nasıl yapılacağını gösterir.
CanReadType ve CanWriteType'ı Geçersiz Kılma
veya yöntemlerini geçersiz kılarak CanReadType CanWriteType içinde seri durumdan çıkarmak veya serileştirmek için türünü belirtin. Örneğin, bir Contact
türden vCard metni oluşturmak için (veya tam tersi):
protected override bool CanWriteType(Type type)
{
return typeof(Contact).IsAssignableFrom(type) ||
typeof(IEnumerable<Contact>).IsAssignableFrom(type);
}
CanWriteResult yöntemi
Bazı senaryolarda yerine CanWriteResult geçersiz kılınmalıdır CanWriteType. Aşağıdaki koşullar doğruysa kullanın CanWriteResult
:
- Eylem yöntemi bir model sınıfı döndürür.
- Çalışma zamanında döndürülebilecek türetilmiş sınıflar vardır.
- Eylem tarafından döndürülen türetilmiş sınıfın çalışma zamanında bilinmesi gerekir.
Örneğin, eylem yöntemini varsayalım:
- İmza bir
Person
tür döndürür. - türünden
Person
türetilen birStudent
veyaInstructor
türü döndürebilir.
Biçimlendiricinin yalnızca Student
nesneleri işlemesi için yöntemine CanWriteResult
sağlanan bağlam nesnesindeki türünü Object denetleyin. Eylem yöntemi döndürdüğünde IActionResult:
- kullanmak
CanWriteResult
gerekli değildir. - yöntemi çalışma
CanWriteType
zamanı türünü alır.
ReadRequestBodyAsync ve WriteResponseBodyAsync'i geçersiz kılma
Seri durumdan çıkarma veya serileştirme veya veya WriteResponseBodyAsynciçinde ReadRequestBodyAsync gerçekleştirilir. Aşağıdaki örnekte, bağımlılık ekleme kapsayıcısından hizmetlerin nasıl alınacakları gösterilmektedir. Hizmetler oluşturucu parametrelerinden alınamaz:
public override async Task WriteResponseBodyAsync(
OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var httpContext = context.HttpContext;
var serviceProvider = httpContext.RequestServices;
var logger = serviceProvider.GetRequiredService<ILogger<VcardOutputFormatter>>();
var buffer = new StringBuilder();
if (context.Object is IEnumerable<Contact> contacts)
{
foreach (var contact in contacts)
{
FormatVcard(buffer, contact, logger);
}
}
else
{
FormatVcard(buffer, (Contact)context.Object, logger);
}
await httpContext.Response.WriteAsync(buffer.ToString(), selectedEncoding);
}
private static void FormatVcard(
StringBuilder buffer, Contact contact, ILogger logger)
{
buffer.AppendLine("BEGIN:VCARD");
buffer.AppendLine("VERSION:2.1");
buffer.AppendLine($"N:{contact.LastName};{contact.FirstName}");
buffer.AppendLine($"FN:{contact.FirstName} {contact.LastName}");
buffer.AppendLine($"UID:{contact.Id}");
buffer.AppendLine("END:VCARD");
logger.LogInformation("Writing {FirstName} {LastName}",
contact.FirstName, contact.LastName);
}
MVC'yi özel biçimlendirici kullanacak şekilde yapılandırma
Özel bir biçimlendirici kullanmak için veya MvcOptions.OutputFormatters koleksiyonuna biçimlendirici sınıfının bir örneğini MvcOptions.InputFormatters ekleyin:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
});
}
Biçimlendiriciler, eklediğiniz sırayla değerlendirilir. İlki önceliklidir.
Tam VcardInputFormatter
sınıf
Aşağıdaki kod, örnekteki VcardInputFormatter
sınıfı gösterir:
public class VcardInputFormatter : TextInputFormatter
{
public VcardInputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
protected override bool CanReadType(Type type)
{
return type == typeof(Contact);
}
public override async Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context, Encoding effectiveEncoding)
{
var httpContext = context.HttpContext;
var serviceProvider = httpContext.RequestServices;
var logger = serviceProvider.GetRequiredService<ILogger<VcardInputFormatter>>();
using var reader = new StreamReader(httpContext.Request.Body, effectiveEncoding);
string nameLine = null;
try
{
await ReadLineAsync("BEGIN:VCARD", reader, context, logger);
await ReadLineAsync("VERSION:", reader, context, logger);
nameLine = await ReadLineAsync("N:", reader, context, logger);
var split = nameLine.Split(";".ToCharArray());
var contact = new Contact
{
LastName = split[0].Substring(2),
FirstName = split[1]
};
await ReadLineAsync("FN:", reader, context, logger);
await ReadLineAsync("END:VCARD", reader, context, logger);
logger.LogInformation("nameLine = {nameLine}", nameLine);
return await InputFormatterResult.SuccessAsync(contact);
}
catch
{
logger.LogError("Read failed: nameLine = {nameLine}", nameLine);
return await InputFormatterResult.FailureAsync();
}
}
private static async Task<string> ReadLineAsync(
string expectedText, StreamReader reader, InputFormatterContext context,
ILogger logger)
{
var line = await reader.ReadLineAsync();
if (!line.StartsWith(expectedText))
{
var errorMessage = $"Looked for '{expectedText}' and got '{line}'";
context.ModelState.TryAddModelError(context.ModelName, errorMessage);
logger.LogError(errorMessage);
throw new Exception(errorMessage);
}
return line;
}
}
Uygulamayı test etme
Temel vCard giriş ve çıkış biçimlendiricilerini uygulayan bu makale için örnek uygulamayı çalıştırın. Uygulama, vCard'ları aşağıdaki biçime benzer şekilde okur ve yazar:
BEGIN:VCARD
VERSION:2.1
N:Davolio;Nancy
FN:Nancy Davolio
END:VCARD
vCard çıkışını görmek için uygulamayı çalıştırın ve accept üst bilgisini text/vcard
https://localhost:5001/api/contacts
içeren bir Get isteği gönderin.
Kişilerden oluşan bellek içi koleksiyona vCard eklemek için:
- Curl gibi bir
Post
araçla adresine/api/contacts
istek gönderin. Content-Type
Üst bilgiyi olaraktext/vcard
ayarlayın.- Gövdedeki metni önceki örnekte olduğu gibi biçimlendirilmiş olarak ayarlayın
vCard
.
Ek kaynaklar
ASP.NET Core