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.
ASP.NET Core MVC támogatja a webes API-kban az adatcserét bemeneti és kimeneti formázók használatával. A bemeneti formázókat a modellkötés használja. A kimeneti formázók a válaszok formázására szolgálnak.
A keretrendszer beépített bemeneti és kimeneti formátumokat biztosít a JSON-hoz és az XML-hez. Beépített kimeneti formátumot biztosít az egyszerű szöveghez, de nem biztosít bemeneti formázót az egyszerű szöveghez.
Ez a cikk bemutatja, hogyan hozhat létre saját formázókat a további formátumok támogatásának érdekében. Példa egy egyszerű szöveges beviteli formátumra: TextPlainInInputFormatter a GitHubon.
Mintakód megtekintése vagy letöltése (hogyan töltsd le)
Mikor érdemes egyéni formázót használni?
Egyéni formázó használatával olyan tartalomtípust támogathat, amelyet nem a beépített formázók kezelnek.
Egyéni formázó létrehozásának áttekintése
Egyéni formázó létrehozásához:
- Az ügyfélnek küldött adatok szerializálásához hozzon létre egy kimeneti formázó osztályt.
- Az ügyféltől kapott adatok deszerializálásához hozzon létre egy bemeneti formázó osztályt.
- Formázóosztályok példányait adja hozzá a InputFormatters és OutputFormatters gyűjteményekhez a MvcOptions-ben.
Egyéni formázó létrehozása
Formázó létrehozása:
- Az osztályt a megfelelő alaposztályból származtatjuk. A mintaalkalmazás a következőkből származik: TextOutputFormatter és TextInputFormatter.
- Adja meg a támogatott médiatípusokat és kódolásokat a konstruktorban.
- Írja felül a CanReadType és CanWriteType metódusokat.
- Írja felül a ReadRequestBodyAsync és WriteResponseBodyAsync metódusokat.
Az alábbi kód a VcardOutputFormattermintából származó osztályt mutatja be:
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);
}
}
Származtasson a megfelelő alaposztályból
Szöveges médiatípusokhoz (például vCard) az TextInputFormatter vagy TextOutputFormatter alaposztályból kell származtatni:
public class VcardOutputFormatter : TextOutputFormatter
Bináris típusok esetén az InputFormatterOutputFormatter alaposztályból származtatható.
Támogatott médiatípusok és kódolások megadása
A konstruktorban adja meg a támogatott médiatípusokat és kódolásokat úgy, hogy hozzáadja azokat a SupportedMediaTypes és SupportedEncodings gyűjteményekhez:
public VcardOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
A formázóosztályok nem használhatnak konstruktorinjektálást a függőségeihez. Például ILogger<VcardOutputFormatter> nem adható hozzá paraméterként a konstruktorhoz. A szolgáltatások eléréséhez használja a metódusok számára átadott környezeti objektumot. A jelen cikkben és a mintában szereplő kód példája bemutatja, hogyan teheti ezt meg.
CanReadType és CanWriteType felülbírálása
Adja meg azt a típust, amelybe deszerializálni vagy amelyből szerializálni szeretne a CanReadType vagy CanWriteType metódusok felülírásával. Például szöveg létrehozása vCard típusból Contact és fordítva:
protected override bool CanWriteType(Type? type)
=> typeof(Contact).IsAssignableFrom(type)
|| typeof(IEnumerable<Contact>).IsAssignableFrom(type);
A CanWriteResult metódus
Bizonyos esetekben a CanWriteResult felülbírálása szükséges ahelyett, hogy a CanWriteType-et felül kellene bírálni. Használja CanWriteResult a következő feltételek teljesülése esetén:
- A műveletmetódus egy modellosztályt ad vissza.
- Vannak származtatott osztályok, amelyeket futásidőben lehet visszaadni.
- A művelet által visszaadott származtatott osztálynak futásidőben ismertnek kell lennie.
Tegyük fel például, hogy a művelet metódusa:
- Az aláírás visszaad egy
Persontípust. - Visszaadhat egy
StudentvagyInstructortípust, amelyPerson-ből származik.
Ha a formázó csak Student objektumokat szeretne kezelni, ellenőrizze a metódushoz Object megadott környezeti objektum típusátCanWriteResult. Amikor a műveletfüggvény a következőt adja vissza: IActionResult
- Nem szükséges használni
CanWriteResult. - A
CanWriteTypemetódus megkapja a futtatókörnyezet típusát.
A ReadRequestBodyAsync és a WriteResponseBodyAsync felülbírálása
A deszerializálás vagy a szerializálás a ReadRequestBodyAsync vagy WriteResponseBodyAsync helyen történik. Az alábbi példa bemutatja, hogyan kérhet le szolgáltatásokat a függőséginjektálási tárolóból. A szolgáltatások nem kérhetők le konstruktorparaméterekből:
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);
}
Az MVC konfigurálása egyéni formázó használatára
Egyéni formázó használatához adja hozzá a formázóosztály egy példányát a MvcOptions.InputFormatters vagy MvcOptions.OutputFormatters gyűjteményhez.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
});
A formázókat a beillesztett sorrendben értékelik ki, amelyben az első élvez elsőbbséget.
A teljes VcardInputFormatter osztály
Az alábbi kód a VcardInputFormattermintából származó osztályt mutatja be:
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;
}
}
Az alkalmazás tesztelése
Futtassa a cikkhez tartozó mintaalkalmazást, amely alapszintű vCard bemeneti és kimeneti formátumokat implementál. Az alkalmazás a következő formátumhoz hasonló vCard-fájlokat olvas és ír:
BEGIN:VCARD
VERSION:2.1
N:Davolio;Nancy
FN:Nancy Davolio
END:VCARD
A vCard kimenetének megtekintéséhez futtassa az alkalmazást, és küldjön egy GET-kérést Accept fejléccel text/vcardhttps://localhost:<port>/api/contacts.
Egy vCard hozzáadása a névjegyek gyűjteményének memóriájába:
- Küldjön egy
Postkérést a/api/contactsszámára egy olyan eszközzel, mint a http-repl. - Állítsa a
Content-Typefejlécettext/vcardértékre. - Állítsa be
vCarda szövegtörzsben az előző példához hasonlóan formázott szöveget.
További erőforrások
ASP.NET Core MVC támogatja a webes API-kban az adatcserét bemeneti és kimeneti formázók használatával. A bemeneti formázókat a modellkötés használja. A kimeneti formázók a válaszok formázására szolgálnak.
A keretrendszer beépített bemeneti és kimeneti formátumokat biztosít a JSON-hoz és az XML-hez. Beépített kimeneti formátumot biztosít az egyszerű szöveghez, de nem biztosít bemeneti formázót az egyszerű szöveghez.
Ez a cikk bemutatja, hogyan hozhat létre saját formázókat a további formátumok támogatásának érdekében. Példa egy egyszerű szöveges beviteli formátumra: TextPlainInInputFormatter a GitHubon.
Mintakód megtekintése vagy letöltése (hogyan töltsd le)
Mikor érdemes egyéni formázót használni?
Egyéni formázó használatával olyan tartalomtípust támogathat, amelyet nem a beépített formázók kezelnek.
Egyéni formázó létrehozásának áttekintése
Egyéni formázó létrehozásához:
- Az ügyfélnek küldött adatok szerializálásához hozzon létre egy kimeneti formázó osztályt.
- Az ügyféltől kapott adatok deszerializálásához hozzon létre egy bemeneti formázó osztályt.
- Formázóosztályok példányait adja hozzá a InputFormatters és OutputFormatters gyűjteményekhez a MvcOptions-ben.
Egyéni formázó létrehozása
Formázó létrehozása:
- Az osztályt a megfelelő alaposztályból származtatjuk. A mintaalkalmazás a következőkből származik: TextOutputFormatter és TextInputFormatter.
- Adja meg a támogatott médiatípusokat és kódolásokat a konstruktorban.
- Írja felül a CanReadType és CanWriteType metódusokat.
- Írja felül a ReadRequestBodyAsync és WriteResponseBodyAsync metódusokat.
Az alábbi kód a VcardOutputFormattermintából származó osztályt mutatja be:
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);
}
}
Származtasson a megfelelő alaposztályból
Szöveges médiatípusokhoz (például vCard) az TextInputFormatter vagy TextOutputFormatter alaposztályból kell származtatni:
public class VcardOutputFormatter : TextOutputFormatter
Bináris típusok esetén az InputFormatterOutputFormatter alaposztályból származtatható.
Támogatott médiatípusok és kódolások megadása
A konstruktorban adja meg a támogatott médiatípusokat és kódolásokat úgy, hogy hozzáadja azokat a SupportedMediaTypes és SupportedEncodings gyűjteményekhez:
public VcardOutputFormatter()
{
SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
SupportedEncodings.Add(Encoding.UTF8);
SupportedEncodings.Add(Encoding.Unicode);
}
A formázóosztályok nem használhatnak konstruktorinjektálást a függőségeihez. Például ILogger<VcardOutputFormatter> nem adható hozzá paraméterként a konstruktorhoz. A szolgáltatások eléréséhez használja a metódusok számára átadott környezeti objektumot. A jelen cikkben és a mintában szereplő kód példája bemutatja, hogyan teheti ezt meg.
CanReadType és CanWriteType felülbírálása
Adja meg azt a típust, amelybe deszerializálni vagy amelyből szerializálni szeretne a CanReadType vagy CanWriteType metódusok felülírásával. Például szöveg létrehozása vCard típusból Contact és fordítva:
protected override bool CanWriteType(Type type)
{
return typeof(Contact).IsAssignableFrom(type) ||
typeof(IEnumerable<Contact>).IsAssignableFrom(type);
}
A CanWriteResult metódus
Bizonyos esetekben a CanWriteResult felülbírálása szükséges ahelyett, hogy a CanWriteType-et felül kellene bírálni. Használja CanWriteResult a következő feltételek teljesülése esetén:
- A műveletmetódus egy modellosztályt ad vissza.
- Vannak származtatott osztályok, amelyeket futásidőben lehet visszaadni.
- A művelet által visszaadott származtatott osztálynak futásidőben ismertnek kell lennie.
Tegyük fel például, hogy a művelet metódusa:
- Az aláírás visszaad egy
Persontípust. - Visszaadhat egy
StudentvagyInstructortípust, amelyPerson-ből származik.
Ha a formázó csak Student objektumokat szeretne kezelni, ellenőrizze a metódushoz Object megadott környezeti objektum típusátCanWriteResult. Amikor a műveletfüggvény a következőt adja vissza: IActionResult
- Nem szükséges használni
CanWriteResult. - A
CanWriteTypemetódus megkapja a futtatókörnyezet típusát.
A ReadRequestBodyAsync és a WriteResponseBodyAsync felülbírálása
A deszerializálás vagy a szerializálás a ReadRequestBodyAsync vagy WriteResponseBodyAsync helyen történik. Az alábbi példa bemutatja, hogyan kérhet le szolgáltatásokat a függőséginjektálási tárolóból. A szolgáltatások nem kérhetők le konstruktorparaméterekből:
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);
}
Az MVC konfigurálása egyéni formázó használatára
Egyéni formázó használatához adja hozzá a formázóosztály egy példányát a MvcOptions.InputFormatters vagy MvcOptions.OutputFormatters gyűjteményhez.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.InputFormatters.Insert(0, new VcardInputFormatter());
options.OutputFormatters.Insert(0, new VcardOutputFormatter());
});
}
A formázók a beszúrt sorrendben lesznek kiértékelve. Az első elsőbbséget élvez.
A teljes VcardInputFormatter osztály
Az alábbi kód a VcardInputFormattermintából származó osztályt mutatja be:
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;
}
}
Az alkalmazás tesztelése
Futtassa a cikkhez tartozó mintaalkalmazást, amely alapszintű vCard bemeneti és kimeneti formátumokat implementál. Az alkalmazás a következő formátumhoz hasonló vCard-fájlokat olvas és ír:
BEGIN:VCARD
VERSION:2.1
N:Davolio;Nancy
FN:Nancy Davolio
END:VCARD
A vCard kimenetének megtekintéséhez futtassa az alkalmazást, és küldjön egy GET-kérést Accept fejléccel text/vcardhttps://localhost:5001/api/contacts.
Egy vCard hozzáadása a névjegyek gyűjteményének memóriájába:
- Küldjön egy
Postkérést a/api/contactsrészére egy olyan eszközzel, mint a curl. - Állítsa a
Content-Typefejlécettext/vcardértékre. - Állítsa be
vCarda szövegtörzsben az előző példához hasonlóan formázott szöveget.