Freigeben über


Medienformatierer in ASP.NET-Web-API 2

In diesem Tutorial wird gezeigt, wie Sie zusätzliche Medienformate in ASP.NET-Web-API unterstützen.

Internetmedientypen

Ein Medientyp, der auch als MIME-Typ bezeichnet wird, gibt das Format eines Datenteils an. In HTTP beschreiben Medientypen das Format des Nachrichtentexts. Ein Medientyp besteht aus zwei Zeichenfolgen, einem Typ und einem Untertyp. Zum Beispiel:

  • text/html
  • image/png
  • Anwendung/json

Wenn eine HTTP-Nachricht einen Entitätstext enthält, gibt der Content-Type-Header das Format des Nachrichtentexts an. Dadurch wird dem Empfänger mitgeteilt, wie der Inhalt des Nachrichtentexts analysiert werden soll.

Wenn beispielsweise eine HTTP-Antwort ein PNG-Bild enthält, kann die Antwort die folgenden Header aufweisen.

HTTP/1.1 200 OK
Content-Length: 95267
Content-Type: image/png

Wenn der Client eine Anforderungsnachricht sendet, kann er einen Accept-Header enthalten. Der Accept-Header teilt dem Server mit, welche Medientypen der Client vom Server wünscht. Zum Beispiel:

Accept: text/html,application/xhtml+xml,application/xml

Dieser Header teilt dem Server mit, dass der Client HTML, XHTML oder XML wünscht.

Der Medientyp bestimmt, wie die Web-API den HTTP-Nachrichtentext serialisiert und deserialisiert. Die Web-API verfügt über integrierte Unterstützung für XML-, JSON-, BSON- und Formular-URLencoded-Daten, und Sie können zusätzliche Medientypen unterstützen, indem Sie einen Medienformatierer schreiben.

Um einen Medienformatierer zu erstellen, leiten Sie von einer der folgenden Klassen ab:

Das Ableiten von BufferedMediaTypeFormatter ist einfacher, da es keinen asynchronen Code gibt, aber es bedeutet auch, dass der aufrufende Thread während der E/A blockieren kann.

Beispiel: Erstellen eines CSV-Medienformatierers

Das folgende Beispiel zeigt einen Medientypformatierer, der ein Product-Objekt in ein CSV-Format (Kommagetrennte Werte) serialisieren kann. In diesem Beispiel wird der Produkttyp verwendet, der im Tutorial Erstellen einer Web-API definiert ist, die CRUD-Vorgänge unterstützt. Hier ist die Definition des Product-Objekts:

namespace ProductStore.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; }
        public decimal Price { get; set; }
    }
}

Um einen CSV-Formatter zu implementieren, definieren Sie eine Klasse, die von BufferedMediaTypeFormatter abgeleitet ist:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using ProductStore.Models;

namespace ProductStore.Formatters
{
    public class ProductCsvFormatter : BufferedMediaTypeFormatter
    {
    }
}

Fügen Sie im Konstruktor die vom Formatierer unterstützten Medientypen hinzu. In diesem Beispiel unterstützt der Formatierer den einzelnen Medientyp "text/csv":

public ProductCsvFormatter()
{
    // Add the supported media type.
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}

Überschreiben Sie die CanWriteType-Methode , um anzugeben, welche Typen der Formatierer serialisieren kann:

public override bool CanWriteType(System.Type type)
{
    if (type == typeof(Product))
    {
        return true;
    }
    else
    {
        Type enumerableType = typeof(IEnumerable<Product>);
        return enumerableType.IsAssignableFrom(type);
    }
}

In diesem Beispiel kann der Formatierer einzelne Product Objekte sowie Sammlungen von Product Objekten serialisieren.

Überschreiben Sie auf ähnliche Weise die CanReadType-Methode , um anzugeben, welche Typen der Formatierer deserialisieren kann. In diesem Beispiel unterstützt der Formatierer die Deserialisierung nicht, sodass die Methode einfach false zurückgibt.

public override bool CanReadType(Type type)
{
    return false;
}

Überschreiben Sie schließlich die WriteToStream-Methode . Diese Methode serialisiert einen Typ, indem er in einen Stream geschrieben wird. Wenn Ihr Formatierer deserialisierung unterstützt, überschreiben Sie auch die ReadFromStream-Methode .

public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
    using (var writer = new StreamWriter(writeStream))
    {
        var products = value as IEnumerable<Product>;
        if (products != null)
        {
            foreach (var product in products)
            {
                WriteItem(product, writer);
            }
        }
        else
        {
            var singleProduct = value as Product;
            if (singleProduct == null)
            {
                throw new InvalidOperationException("Cannot serialize type");
            }
            WriteItem(singleProduct, writer);
        }
    }
}

// Helper methods for serializing Products to CSV format. 
private void WriteItem(Product product, StreamWriter writer)
{
    writer.WriteLine("{0},{1},{2},{3}", Escape(product.Id),
        Escape(product.Name), Escape(product.Category), Escape(product.Price));
}

static char[] _specialChars = new char[] { ',', '\n', '\r', '"' };

private string Escape(object o)
{
    if (o == null)
    {
        return "";
    }
    string field = o.ToString();
    if (field.IndexOfAny(_specialChars) != -1)
    {
        // Delimit the entire field with quotes and replace embedded quotes with "".
        return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
    }
    else return field;
}

Hinzufügen eines Medienformatierers zur Web-API-Pipeline

Um der Web-API-Pipeline einen Medientypformatierer hinzuzufügen, verwenden Sie die Formatters-Eigenschaft für das HttpConfiguration-Objekt .

public static void ConfigureApis(HttpConfiguration config)
{
    config.Formatters.Add(new ProductCsvFormatter()); 
}

Zeichencodierungen

Optional kann ein Medienformatierer mehrere Zeichencodierungen wie UTF-8 oder ISO 8859-1 unterstützen.

Fügen Sie im Konstruktor der SupportedEncodings-Auflistung einen oder mehrere System.Text.Encoding-Typen hinzu. Legen Sie die Standardcodierung an erster Stelle.

public ProductCsvFormatter()
{
    SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));

    // New code:
    SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
    SupportedEncodings.Add(Encoding.GetEncoding("iso-8859-1"));
}

Rufen Sie in den Methoden WriteToStream und ReadFromStreamMediaTypeFormatter.SelectCharacterEncoding auf, um die bevorzugte Zeichencodierung auszuwählen. Diese Methode gleicht die Anforderungsheader mit der Liste der unterstützten Codierungen ab. Verwenden Sie die zurückgegebene Codierung , wenn Sie aus dem Stream lesen oder schreiben:

public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
{
    Encoding effectiveEncoding = SelectCharacterEncoding(content.Headers);

    using (var writer = new StreamWriter(writeStream, effectiveEncoding))
    {
        // Write the object (code not shown)
    }
}