Formateurs de médias dans API Web ASP.NET 2

Ce tutoriel montre comment prendre en charge des formats multimédias supplémentaires dans API Web ASP.NET.

Types de médias Internet

Un type de média, également appelé type MIME, identifie le format d’un élément de données. Dans HTTP, les types de média décrivent le format du corps du message. Un type de média se compose de deux chaînes, un type et un sous-type. Par exemple :

  • texte/html
  • image/png
  • application/json

Lorsqu’un message HTTP contient un corps d’entité, l’en-tête Content-Type spécifie le format du corps du message. Cela indique au destinataire comment analyser le contenu du corps du message.

Par exemple, si une réponse HTTP contient une image PNG, la réponse peut avoir les en-têtes suivants.

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

Lorsque le client envoie un message de demande, il peut inclure un en-tête Accepter. L’en-tête Accepter indique au serveur le ou les types de média que le client souhaite du serveur. Par exemple :

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

Cet en-tête indique au serveur que le client souhaite du code HTML, XHTML ou XML.

Le type de média détermine comment l’API web sérialise et désérialise le corps du message HTTP. L’API web prend en charge les données XML, JSON, BSON et form-urlencode, et vous pouvez prendre en charge d’autres types de médias en écrivant un formateur multimédia.

Pour créer un formateur multimédia, dérivez de l’une des classes suivantes :

  • MediaTypeFormatter. Cette classe utilise des méthodes de lecture et d’écriture asynchrones.
  • BufferedMediaTypeFormatter. Cette classe dérive de MediaTypeFormatter , mais utilise des méthodes de lecture/écriture synchrones.

La dérivation de BufferedMediaTypeFormatter est plus simple, car il n’y a pas de code asynchrone, mais cela signifie également que le thread appelant peut se bloquer pendant les E/S.

Exemple : création d’un formateur multimédia CSV

L’exemple suivant montre un formateur de type média qui peut sérialiser un objet Product au format CSV (Valeurs séparées par des virgules). Cet exemple utilise le type de produit défini dans le didacticiel Création d’une API web qui prend en charge les opérations CRUD. Voici la définition de l’objet Product :

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; }
    }
}

Pour implémenter un formateur CSV, définissez une classe qui dérive de BufferedMediaTypeFormatter :

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
    {
    }
}

Dans le constructeur, ajoutez les types de supports pris en charge par le formateur. Dans cet exemple, le formateur prend en charge un type de média unique, « text/csv » :

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

Remplacez la méthode CanWriteType pour indiquer les types que le formateur peut sérialiser :

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

Dans cet exemple, le formateur peut sérialiser des objets uniques Product ainsi que des collections d’objets Product .

De même, remplacez la méthode CanReadType pour indiquer les types que le formateur peut désérialiser. Dans cet exemple, le formateur ne prend pas en charge la désérialisation. La méthode retourne donc simplement false.

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

Enfin, remplacez la méthode WriteToStream . Cette méthode sérialise un type en l’écrivant dans un flux. Si votre formateur prend en charge la désérialisation, remplacez également la méthode ReadFromStream .

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;
}

Ajout d’un formateur multimédia au pipeline d’API web

Pour ajouter un formateur de type de média au pipeline d’API web, utilisez la propriété Formateurs sur l’objet HttpConfiguration .

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

Encodages de caractères

Si vous le souhaitez, un formateur multimédia peut prendre en charge plusieurs encodages de caractères, tels que UTF-8 ou ISO 8859-1.

Dans le constructeur, ajoutez un ou plusieurs types System.Text.Encoding à la collection SupportedEncodings . Placez l’encodage par défaut en premier.

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

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

Dans les méthodes WriteToStream et ReadFromStream , appelez MediaTypeFormatter.SelectCharacterEncoding pour sélectionner l’encodage de caractères préféré. Cette méthode met en correspondance les en-têtes de requête par rapport à la liste des encodages pris en charge. Utilisez l’encodage retourné lorsque vous lisez ou écrivez à partir du flux :

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)
    }
}