Programy formatujące multimedia w interfejsie API sieci Web ASP.NET 2
W tym samouczku pokazano, jak obsługiwać dodatkowe formaty multimediów w interfejsie API sieci Web ASP.NET.
Typy multimediów internetowych
Typ nośnika, nazywany również typem MIME, identyfikuje format elementu danych. W przypadku protokołu HTTP typy multimediów opisują format treści komunikatu. Typ nośnika składa się z dwóch ciągów, typu i podtypu. Na przykład:
- text/html
- image/png
- application/json
Gdy komunikat HTTP zawiera treść jednostki, nagłówek Content-Type określa format treści komunikatu. Informuje to odbiorcę, jak analizować zawartość treści komunikatu.
Jeśli na przykład odpowiedź HTTP zawiera obraz PNG, odpowiedź może zawierać następujące nagłówki.
HTTP/1.1 200 OK
Content-Length: 95267
Content-Type: image/png
Gdy klient wysyła komunikat żądania, może on zawierać nagłówek Accept. Nagłówek Accept informuje serwer o typach nośników, których klient chce z serwera. Na przykład:
Accept: text/html,application/xhtml+xml,application/xml
Ten nagłówek informuje serwer, że klient chce użyć kodu HTML, XHTML lub XML.
Typ nośnika określa, jak internetowy interfejs API serializuje i deserializuje treść komunikatu HTTP. Internetowy interfejs API ma wbudowaną obsługę danych XML, JSON, BSON i danych zakodowanych w postaci adresów URL. Można również obsługiwać dodatkowe typy multimediów, zapisując formater multimediów.
Aby utworzyć program formatujący multimedia, należy utworzyć jedną z następujących klas:
- MediaTypeFormatter. Ta klasa używa asynchronicznych metod odczytu i zapisu.
- BufferedMediaTypeFormatter. Ta klasa pochodzi z klasy MediaTypeFormatter , ale używa synchronicznych metod odczytu/zapisu.
Wyprowadzanie z BufferedMediaTypeFormatter jest prostsze, ponieważ nie ma kodu asynchronicznego, ale oznacza to również, że wątek wywołujący może blokować podczas we/wy.
Przykład: tworzenie formatu multimediów CSV
W poniższym przykładzie pokazano formatujący typ nośnika, który może serializować obiekt Product w formacie wartości rozdzielanych przecinkami (CSV). W tym przykładzie użyto typu Product zdefiniowanego w samouczku Tworzenie internetowego interfejsu API obsługującego operacje CRUD. Oto definicja obiektu 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; }
}
}
Aby zaimplementować program formatujący CSV, zdefiniuj klasę pochodną 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
{
}
}
W konstruktorze dodaj typy multimediów obsługiwane przez program formatujący. W tym przykładzie formatator obsługuje jeden typ nośnika "text/csv":
public ProductCsvFormatter()
{
// Add the supported media type.
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}
Zastąp metodę CanWriteType , aby wskazać typy, które formater może serializować:
public override bool CanWriteType(System.Type type)
{
if (type == typeof(Product))
{
return true;
}
else
{
Type enumerableType = typeof(IEnumerable<Product>);
return enumerableType.IsAssignableFrom(type);
}
}
W tym przykładzie program formatujący może serializować pojedyncze Product
obiekty, a także kolekcje Product
obiektów.
Podobnie zastąpij metodę CanReadType , aby wskazać typy, które formater może deserializować. W tym przykładzie formater nie obsługuje deserializacji, więc metoda po prostu zwraca wartość false.
public override bool CanReadType(Type type)
{
return false;
}
Na koniec przesłoń metodę WriteToStream . Ta metoda serializuje typ, zapisując go w strumieniu. Jeśli formater obsługuje deserializacji, należy również zastąpić metodę 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;
}
Dodawanie programu Media Formatter do potoku internetowego interfejsu API
Aby dodać formatter typów multimediów do potoku internetowego interfejsu API, użyj właściwości Formatters w obiekcie HttpConfiguration .
public static void ConfigureApis(HttpConfiguration config)
{
config.Formatters.Add(new ProductCsvFormatter());
}
Kodowania znaków
Opcjonalnie formater multimediów może obsługiwać wiele kodowań znaków, takich jak UTF-8 lub ISO 8859-1.
W konstruktorze dodaj co najmniej jeden typ System.Text.Encoding do kolekcji SupportedEncodings . Najpierw umieść domyślne kodowanie.
public ProductCsvFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
// New code:
SupportedEncodings.Add(new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
SupportedEncodings.Add(Encoding.GetEncoding("iso-8859-1"));
}
W metodach WriteToStream i ReadFromStream wywołaj metodę MediaTypeFormatter.SelectCharacterEncoding , aby wybrać preferowane kodowanie znaków. Ta metoda dopasuje nagłówki żądań do listy obsługiwanych kodowań. Użyj zwróconego kodowania podczas odczytu lub zapisu ze strumienia:
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)
}
}