Partilhar via


Formatadores de Media na ASP.NET Web API 2

Este tutorial mostra como suportar formatos de media adicionais na ASP.NET Web API.

Tipos de Media na Internet

Um tipo de media, também chamado de tipo MIME, identifica o formato de um dado. Em HTTP, os tipos de media descrevem o formato do corpo da mensagem. Um tipo de media consiste em duas cadeias, um tipo e um subtipo. Por exemplo:

  • texto/html
  • tipo de ficheiro imagem/png
  • application/json

Quando uma mensagem HTTP contém um corpo-entidade, o cabeçalho Content-Type especifica o formato do corpo da mensagem. Isto indica ao destinatário como analisar o conteúdo do corpo da mensagem.

Por exemplo, se uma resposta HTTP contiver uma imagem PNG, a resposta pode ter os seguintes cabeçalhos.

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

Quando o cliente envia uma mensagem de pedido, pode incluir um cabeçalho Aceitar. O cabeçalho Aceitar indica ao servidor que tipo(s) de media o cliente quer do servidor. Por exemplo:

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

Este cabeçalho indica ao servidor que o cliente quer HTML, XHTML ou XML.

O tipo de media determina como a Web API serializa e desserializa o corpo da mensagem HTTP. A Web API tem suporte incorporado para dados XML, JSON, BSON e form-urlencoded, e pode suportar tipos de mídia adicionais escrevendo um formatador de mídia.

Para criar um formatador de media, derive de uma destas classes:

Derivar de BufferedMediaTypeFormatter é mais simples, porque não existe um código assíncrono, mas também significa que a chamada pode ser bloqueada durante operações de I/O.

Exemplo: Criação de um Formatador de Media CSV

O exemplo seguinte mostra um formatador de tipo media que pode serializar um objeto Product para um formato de valores separados por vírgulas (CSV). Este exemplo utiliza o tipo de produto definido no tutorial Criar uma API Web que Suporta Operações CRUD. Aqui está a definição do objeto Produto:

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

Para implementar um formatador CSV, defina uma classe que derive 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
    {
    }
}

No construtor, adicione os tipos de mídia que o formatador suporta. Neste exemplo, o formatador suporta um único tipo de media, "texto/csv":

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

Substitua o método CanWriteType para indicar que tipos o formatador pode serializar:

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

Neste exemplo, o formatador pode serializar objetos individuais Product , bem como coleções de objetos Product .

De forma semelhante, substitua o método CanReadType para indicar que tipos o formatador pode desserializar. Neste exemplo, o formador não suporta desserialização, pelo que o método simplesmente retorna falso.

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

Por fim, substitua o método WriteToStream . Este método serializa um tipo ao escrevê-lo num fluxo. Se o seu formatador suportar desserialização, também substitua o método 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;
}

Adicionar um Formateador de Mídia ao Pipeline da Web API

Para adicionar um formateador de tipo de media ao pipeline da API Web, use a propriedade Formatter no objeto HttpConfiguration .

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

Codificações de Caracteres

Opcionalmente, um formatador de media pode suportar múltiplas codificações de caracteres, como UTF-8 ou ISO 8859-1.

No construtor, adicione um ou mais tipos System.Text.Encoding à coleção SupportedEncodings . Coloque a codificação padrão em primeiro lugar.

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

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

Nos métodos WriteToStream e ReadFromStream , chame MediaTypeFormatter.SelectCharacterEncoding para selecionar a codificação de caracteres preferida. Este método compara os cabeçalhos dos pedidos com a lista de codificações suportadas. Use a codificação devolvida quando ler ou escrever a partir do fluxo:

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