Condividi tramite


Formattatori multimediali nell'API Web ASP.NET 2

Questa esercitazione illustra come supportare formati multimediali aggiuntivi in ASP.NET API Web.

Tipi di supporti Internet

Un tipo di media, detto anche tipo MIME, identifica il formato di un insieme di dati. In HTTP i tipi di media descrivono il formato del corpo del messaggio. Un tipo di media è costituito da due stringhe, un tipo e un sottotipo. Per esempio:

  • text/html
  • image/png
  • application/json

Quando un messaggio HTTP contiene un corpo di entità, l'intestazione Content-Type specifica il formato del corpo del messaggio. Questo indica al ricevitore come analizzare il contenuto del corpo del messaggio.

Ad esempio, se una risposta HTTP contiene un'immagine PNG, la risposta potrebbe avere le intestazioni seguenti.

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

Quando il client invia un messaggio di richiesta, può includere un'intestazione Accept. L'intestazione Accept indica al server quali tipi di supporti il client desidera dal server. Per esempio:

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

Questa intestazione indica al server che il client desidera HTML, XHTML o XML.

Il tipo di supporto determina il modo in cui l'API Web serializza e deserializza il corpo del messaggio HTTP. L'API Web include il supporto predefinito per i dati XML, JSON, BSON e form-urlencoded ed è possibile supportare tipi di supporti aggiuntivi scrivendo un formattatore multimediale.

Per creare un formattatore multimediale, derivare da una di queste classi:

La derivazione da BufferedMediaTypeFormatter è più semplice, perché non esiste codice asincrono, ma significa anche che il thread chiamante può bloccarsi durante l'I/O.

Esempio: Creazione di un formattatore multimediale CSV

Nell'esempio seguente viene illustrato un formattatore di tipo multimediale in grado di serializzare un oggetto Product in un formato csv (Comma-Separated Values). Questo esempio usa il tipo di prodotto definito nell'esercitazione Creazione di un'API Web che supporta operazioni CRUD. Ecco la definizione dell'oggetto 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; }
    }
}

Per implementare un formattatore CSV, definire una classe che deriva da 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
    {
    }
}

Nel costruttore aggiungere i tipi di supporto supportati dal formattatore. In questo esempio il formattatore supporta un singolo tipo di supporto, "text/csv":

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

Eseguire l'override del metodo CanWriteType per indicare quali tipi il formattatore può serializzare:

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

In questo esempio il formattatore può serializzare singoli Product oggetti e raccolte di Product oggetti.

Analogamente, eseguire l'override del metodo CanReadType per indicare quali tipi il formattatore può deserializzare. In questo esempio il formattatore non supporta la deserializzazione, quindi il metodo restituisce semplicemente false.

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

Infine, eseguire l'override del metodo WriteToStream . Questo metodo serializza un tipo scrivendolo in un flusso. Se il formattatore supporta la deserializzazione, eseguire anche l'override del metodo 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;
}

Aggiunta di un formattatore multimediale alla pipeline dell'API Web

Per aggiungere un formattatore del tipo di media alla pipeline dell'API Web, usare la proprietà Formatters nell'oggetto HttpConfiguration.

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

Codifiche di caratteri

Facoltativamente, un formattatore multimediale può supportare più codifiche di caratteri, ad esempio UTF-8 o ISO 8859-1.

Nel costruttore aggiungere uno o più tipi System.Text.Encoding all'insieme SupportedEncodings . Inserire prima la codifica predefinita.

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

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

Nei metodi WriteToStream e ReadFromStream chiamare MediaTypeFormatter.SelectCharacterEncoding per selezionare la codifica dei caratteri preferita. Questo metodo confronta le intestazioni della richiesta con l'elenco delle codifiche supportate. Usare la codifica restituita quando si legge o si scrive dal flusso:

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