Форматировщики мультимедиа в веб-API ASP.NET 2

В этом руководстве показано, как поддерживать дополнительные форматы мультимедиа в веб-API ASP.NET.

Типы мультимедиа в Интернете

Тип мультимедиа, также называемый типом MIME, определяет формат фрагмента данных. В HTTP типы мультимедиа описывают формат текста сообщения. Тип носителя состоит из двух строк: типа и подтипа. Пример:

  • text/html
  • image/png
  • приложение/json

Если HTTP-сообщение содержит тело сущности, заголовок Content-Type указывает формат текста сообщения. Это сообщает получателю, как проанализировать содержимое текста сообщения.

Например, если HTTP-ответ содержит изображение в формате PNG, ответ может содержать следующие заголовки.

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

Когда клиент отправляет сообщение запроса, оно может включать заголовок Accept. Заголовок Accept сообщает серверу, какие типы мультимедиа клиент хочет от сервера. Пример:

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

Этот заголовок сообщает серверу, что клиенту требуется HTML, XHTML или XML.

Тип носителя определяет, как веб-API сериализует и десериализует текст сообщения HTTP. Веб-API имеет встроенную поддержку данных XML, JSON, BSON и form-urlencoded, а вы можете поддерживать дополнительные типы мультимедиа, написав форматировщик мультимедиа.

Чтобы создать форматировщик мультимедиа, наследуйте от одного из следующих классов:

  • MediaTypeFormatter. Этот класс использует асинхронные методы чтения и записи.
  • BufferedMediaTypeFormatter. Этот класс является производным от MediaTypeFormatter, но использует синхронные методы чтения и записи.

Наследование от BufferedMediaTypeFormatter проще, так как не существует асинхронного кода, но это также означает, что вызывающий поток может блокироваться во время ввода-вывода.

Пример. Создание модуля форматирования мультимедиа CSV

В следующем примере показан форматировщик типов мультимедиа, который может сериализовать объект Product в формат значений с разделиющими запятыми (CSV). В этом примере используется тип продукта, определенный в учебнике Создание веб-API, поддерживающего операции CRUD. Ниже приведено определение объекта 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; }
    }
}

Чтобы реализовать форматировщик CSV, определите класс, производный от 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
    {
    }
}

В конструкторе добавьте типы мультимедиа, поддерживаемые форматировщиком. В этом примере модуль форматирования поддерживает один тип мультимедиа "text/csv":

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

Переопределите метод CanWriteType , чтобы указать, какие типы форматировщик может сериализовать:

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

В этом примере модуль форматирования может сериализовать отдельные Product объекты, а также коллекции Product объектов .

Аналогичным образом переопределите метод CanReadType , чтобы указать, какие типы форматировщик может десериализовать. В этом примере форматировщик не поддерживает десериализацию, поэтому метод просто возвращает значение false.

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

Наконец, переопределите метод WriteToStream . Этот метод сериализует тип, записывая его в поток. Если модуль форматирования поддерживает десериализацию, также переопределите метод 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;
}

Добавление модуля форматирования мультимедиа в конвейер веб-API

Чтобы добавить форматировщик типов мультимедиа в конвейер веб-API, используйте свойство Formatters объекта HttpConfiguration .

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

Кодировки символов

При необходимости модуль форматирования мультимедиа может поддерживать несколько кодировок символов, например UTF-8 или ISO 8859-1.

В конструкторе добавьте один или несколько типов System.Text.Encoding в коллекцию SupportedEncodings . Сначала поместите кодировку по умолчанию.

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

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

В методах WriteToStream и ReadFromStream вызовите MediaTypeFormatter.SelectCharacterEncoding , чтобы выбрать предпочтительную кодировку символов. Этот метод сопоставляет заголовки запроса со списком поддерживаемых кодировок. Используйте возвращенную кодировку при чтении или записи из потока:

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