login register Sysop! about ME  
qrcode
    최초 작성일 :    2015년 04월 22일
  최종 수정일 :    2015년 04월 22일
  작성자 :    Taeyo
  편집자 :    Taeyo (김 태영)
  읽음수 :    11,669

강좌 목록으로 돌아가기

필자의 잡담~

안녕하세요, Taeyo입니다.

이번에는 뭐를 번역해볼까 하다가 상대적으로 작지만 알찬 내용이 있어서 번역해 보았습니다.
Web API 2와 관련한 네 번째 글로서 미디어 포매터(Media Formatters)에 대한 이야기랍니다.
이전 강좌에서 언급되었던 녀석이라 궁금해 하셨던 분들도 계시겠죠? 제만 그랬었습니다만.. 헤헷.
앞서 말씀드렸다시피 이게 공식적으로 순서가 있는 상태가 아니라서 제가 알아서판단해서 일단 시리즈처럼 번역해 올리고 있습니다.
본 번역문서는 ASP.NET 기술을 널리 알리고자 하는 개인적인 취지로 번역되어 제공되는 문서로, 원문을 비롯한 모든 저작권은 마이크로소프트사에 있습니다. 마이크로소프트사의 요청이 있을 경우, 언제라도 게시가 중단될 수 있습니다. 본 번역문서에는 오역이 포함되어 있을 수 있으며 주석도 번역자 개인의 견해일뿐입니다. 마이크로소프트사는 본 문서의 번역된 내용에 대해 일체의 보장을 하지 않습니다. 번역이 완료된 뒤에도 제품이 업그레이드 되거나 기능이 변경됨에 따라 원문도 변경되거나 보완되었을 수 있으므로 참고하시기 바랍니다.

이번 강좌는 ASP.NET Web API에서 추가적인 미디어 포맷들을 지원하는 방법을 다룬다.

인터넷 미디어 형식들

MIME 형식이라고도 불리는 미디어 형식은 데이터 조각의 포맷을 나타내는 것이다. HTTP의 경우 미디어 형식은 메시지 본문의 포맷을 의미한다. 미디어 형식은 2개의 문자열로 구성되는데, 그들은 각각 주된 형식과 하위형식이다. 예를 들면, 다음과 같다.

  • text/html
  • image/png
  • application/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 중 하나를 응답 포맷으로 원한다고 서버에게 알려주는 역할을 한다.

미디어 형식은 Web API가 HTTP 메시지 본문을 어떻게 직렬화하고 역직렬화 해야 하는지를 나타낸다. Web API는 기본적으로 XML, JSON, BSON, form-urlencoded 데이터 포맷에 대한 지원을 내장하고 있으며, 여러분이 자체 미디어 포매터(media formatter)를 작성할 경우 추가적인 미디어 형식을 지원할 수도 있다.

미디어 포매터를 만들려면 다음 클래스 중 하나를 상속받아야 한다.

  • MediaTypeFormatter. 이 클래스는 비동기 읽기 및 쓰기 메서드를 사용한다.
  • BufferedMediaTypeFormatter. 이 클래스는 MediaTypeFormatter?클래스에서 파생되지만 동기적인 읽기/쓰기 메서드들을 사용한다는 것이 특징이다.

BufferedMediaTypeFormatter로부터 파생하는 것이 좀 더 간단하긴 하지만(비동기 코드가 존재하지 않으므로), 이렇게 하면 쓰레드를 호출할 경우 I/O 시에 블록이 발생할 수 있다는 단점이 있다.

예제 : CSV 미디어 포매터 만들기

다음 예제는 Product 개체를 CSV 즉, 콤마로 구분되는 값(comma-separated value)으로 직렬화하는 미디어 형식 포매터를 보여준다. 이 예제는? Creating a Web API that Supports CRUD Operations 컬럼에서 다룬 적이 있는 Product 형식을 사용하고 있는데, 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 포매터를 구현하기 위해서는 BufferedMediaTypeFormater에서 파생된 클래스를 정의해야 한다.

namespace ProductStore.Formatters
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;
}

Web API 파이프라인에 미디어 포매터 추가하기

Web API 파이프라인에 미디어 형식 포매터를 추가하려면, HttpConfiguration 개체의 Formatters?속성을 사용해야 한다.

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?를 호출하면 된다. 이 메서드는 요청 헤더들과 지원되는 인코딩 목록을 비교한 뒤 매치되어 반환된 Encoding을 스트림을 읽고 쓸 경우에 사용한다.

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

authored by

  itist
  2015-04-23(10:54)
캐릭 이미지
감사합니다!

 
 
.NET과 Java 동영상 기반의 교육사이트

로딩 중입니다...

서버 프레임워크 지원 : NeoDEEX
based on ASP.NET 3.5
Creative Commons License
{5}
{2} 읽음   :{3} ({4})