다음을 통해 공유


Web API 2를 사용하여 OData v3 엔드포인트 만들기

작성자: Mike Wasson

완료된 프로젝트 다운로드

OData( Open Data Protocol )는 웹용 데이터 액세스 프로토콜입니다. OData는 CRUD 작업(만들기, 읽기, 업데이트 및 삭제)을 통해 데이터를 구조화하고, 데이터를 쿼리하고, 데이터 집합을 조작하는 균일한 방법을 제공합니다. OData는 AtomPub(XML) 및 JSON 형식을 모두 지원합니다. 또한 OData는 데이터에 대한 메타데이터를 노출하는 방법을 정의합니다. 클라이언트는 메타데이터를 사용하여 데이터 집합에 대한 형식 정보 및 관계를 검색할 수 있습니다.

ASP.NET Web API 데이터 집합에 대한 OData 엔드포인트를 쉽게 만들 수 있습니다. 엔드포인트에서 지원하는 OData 작업을 정확히 제어할 수 있습니다. OData가 아닌 엔드포인트와 함께 여러 OData 엔드포인트를 호스트할 수 있습니다. 데이터 모델, 백 엔드 비즈니스 논리 및 데이터 계층을 완전히 제어할 수 있습니다.

자습서에서 사용되는 소프트웨어 버전

Web API OData 지원은 ASP.NET 및 Web Tools 2012.2 업데이트에 추가되었습니다. 그러나 이 자습서에서는 Visual Studio 2013 추가된 스캐폴딩을 사용합니다.

이 자습서에서는 클라이언트가 쿼리할 수 있는 간단한 OData 엔드포인트를 만듭니다. 또한 엔드포인트에 대한 C# 클라이언트를 만듭니다. 이 자습서를 완료한 후 다음 자습서 집합에서는 엔터티 관계, 작업 및 $expand/$select 포함하여 더 많은 기능을 추가하는 방법을 보여 줍니다.

Visual Studio 프로젝트 만들기

이 자습서에서는 기본 CRUD 작업을 지원하는 OData 엔드포인트를 만듭니다. 엔드포인트는 단일 리소스, 제품 목록을 노출합니다. 이후 자습서에서는 더 많은 기능을 추가합니다.

Visual Studio를 시작하고 시작 페이지에서 새 프로젝트를 선택합니다. 또는 파일 메뉴에서 새로 만들기 를 선택한 다음 프로젝트를 선택합니다.

템플릿 창에서 설치된 템플릿을 선택하고 Visual C# 노드를 확장합니다. Visual C#에서 을 선택합니다. ASP.NET 웹 애플리케이션 템플릿을 선택합니다.

템플릿 창의 경로를 보여 주는 새 프로젝트 창의 스크린샷과 강조 표시된 방향을 표시하여 A SP dot NET 웹 애플리케이션 옵션을 선택합니다.

새 ASP.NET 프로젝트 대화 상자에서 템플릿을 선택합니다. "에 대한 폴더 및 핵심 참조 추가..."에서 Web API를 검사. 확인을 클릭합니다.

템플릿 옵션 상자를 표시하고 '빈' 옵션을 강조 표시하는 A SP dot NET 프로젝트 대화 상자의 스크린샷

엔터티 모델 추가

모델은 애플리케이션에서 데이터를 나타내는 개체입니다. 이 자습서에서는 제품을 나타내는 모델이 필요합니다. 모델은 OData 엔터티 형식에 해당합니다.

솔루션 탐색기에서 Models 폴더를 마우스 오른쪽 단추로 클릭합니다. 상황에 맞는 메뉴에서 추가를 선택한 다음 클래스를 선택합니다.

각 선택 영역이 강조 표시되어 클래스 옵션을 선도하는 각 선택 항목의 메뉴 목록을 보여 주는 솔루션 탐색기 대화 상자의 스크린샷

새 항목 추가 대화 상자에서 클래스 이름을 "Product"로 지정합니다.

기본 정렬을 표시하고 클래스 옵션을 표시하는 '새 프로젝트 추가' 창의 스크린샷과 아래 빈 필드에 'product dot c s'라는 단어가 표시됩니다.

참고

규칙에 따라 모델 클래스는 Models 폴더에 배치됩니다. 사용자 고유의 프로젝트에서 이 규칙을 따를 필요는 없지만 이 자습서에는 이 규칙을 사용합니다.

Product.cs 파일에서 다음 클래스 정의를 추가합니다.

public class Product
{
    public int ID { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

ID 속성은 엔터티 키가 됩니다. 클라이언트는 ID로 제품을 쿼리할 수 있습니다. 이 필드는 백 엔드 데이터베이스의 기본 키이기도 합니다.

지금 프로젝트를 빌드합니다. 다음 단계에서는 리플렉션을 사용하여 제품 유형을 찾는 Visual Studio 스캐폴딩을 사용합니다.

OData 컨트롤러 추가

컨트롤러는 HTTP 요청을 처리하는 클래스입니다. OData 서비스에서 설정된 각 엔터티에 대해 별도의 컨트롤러를 정의합니다. 이 자습서에서는 단일 컨트롤러를 만듭니다.

솔루션 탐색기에서 Controllers 폴더를 마우스 오른쪽 단추로 클릭합니다. 추가를 선택한 후 컨트롤러를 선택합니다.

O 데이터 컨트롤러를 추가하는 메뉴를 표시하는 컨트롤러 옵션을 강조 표시하는 솔루션 탐색기 창의 스크린샷

스캐폴드 추가 대화 상자에서 "Entity Framework를 사용하여 작업이 있는 Web API 2 OData 컨트롤러"를 선택합니다.

컨트롤러 옵션 메뉴를 표시하고 Web A P I 2 O 데이터 컨트롤러를 강조 표시하는 '스캐폴드 추가' 화면의 스크린샷

컨트롤러 추가 대화 상자에서 컨트롤러 이름을 "ProductsController"로 지정합니다. "비동기 컨트롤러 작업 사용" 확인란을 선택합니다. 모델 드롭다운 목록에서 Product 클래스를 선택합니다.

컨트롤러 이름, 모델 클래스 드롭다운 목록 및 데이터 컨텍스트 클래스에 대한 필드를 표시하는 컨트롤러 추가 대화 상자의 스크린샷

새 데이터 컨텍스트... 단추를 클릭합니다. 데이터 컨텍스트 형식의 기본 이름을 그대로 두고 추가를 클릭합니다.

'새 데이터 컨텍스트 형식'에 대한 필드를 표시하고 데이터 컨텍스트 형식의 기본 이름을 보여 주는 새 데이터 컨텍스트 창의 스크린샷

컨트롤러 추가 대화 상자에서 추가를 클릭하여 컨트롤러를 추가합니다.

'비동기 컨트롤러 작업 사용' 확인란이 있는 다양한 필드 요구 사항을 보여 주는 컨트롤러 추가 대화 상자의 스크린샷

참고: "형식을 가져오는 동안 오류가 발생했습니다..."라는 오류 메시지가 표시되면 Product 클래스를 추가한 후 Visual Studio 프로젝트를 빌드했는지 확인합니다. 스캐폴딩은 리플렉션을 사용하여 클래스를 찾습니다.

빨간색 원 'X'와 'error'라는 단어와 오류에 대한 자세한 메시지가 표시된 Microsoft Visual Studio의 스크린샷

스캐폴딩은 프로젝트에 두 개의 코드 파일을 추가합니다.

  • Products.cs는 OData 엔드포인트를 구현하는 Web API 컨트롤러를 정의합니다.
  • ProductServiceContext.cs는 Entity Framework를 사용하여 기본 데이터베이스를 쿼리하는 메서드를 제공합니다.

제품 서비스 메뉴를 보여 주는 프로젝트 창의 스크린샷과 컨트롤러 아래와 모델에서 새로 추가된 두 파일을 순환합니다.

EDM 및 경로 추가

솔루션 탐색기 App_Start 폴더를 확장하고 WebApiConfig.cs라는 파일을 엽니다. 이 클래스는 Web API에 대한 구성 코드를 보유합니다. 이 코드를 다음으로 바꿉니다.

using ProductService.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;

namespace ProductService
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.EntitySet<Product>("Products");
            config.Routes.MapODataRoute("odata", "odata", builder.GetEdmModel());
        }
    }
}

이 코드는 다음 두 가지 작업을 수행합니다.

  • OData 엔드포인트에 대한 EDM(엔터티 데이터 모델)을 만듭니다.
  • 엔드포인트에 대한 경로를 추가합니다.

EDM은 데이터의 추상 모델입니다. EDM은 메타데이터 문서를 만들고 서비스에 대한 URI를 정의하는 데 사용됩니다. ODataConventionModelBuilder는 기본 명명 규칙 EDM 집합을 사용하여 EDM을 만듭니다. 이 방법을 사용하려면 최소 코드가 필요합니다. EDM에 대한 더 많은 제어를 원하는 경우 ODataModelBuilder 클래스를 사용하여 속성, 키 및 탐색 속성을 명시적으로 추가하여 EDM을 만들 수 있습니다.

EntitySet 메서드는 엔터티 집합을 EDM에 추가합니다.

modelBuilder.EntitySet<Product>("Products");

문자열 "Products"는 엔터티 집합의 이름을 정의합니다. 컨트롤러 이름은 엔터티 집합의 이름과 일치해야 합니다. 이 자습서에서 엔터티 집합의 이름은 "Products"이고 컨트롤러 이름은 입니다 ProductsController. 엔터티 집합의 이름을 "ProductSet"으로 지정하면 컨트롤러 ProductSetController의 이름을 로 지정합니다. 엔드포인트에는 여러 엔터티 집합이 있을 수 있습니다. 각 엔터티 집합에 대해 EntitySet<T> 를 호출한 다음 해당 컨트롤러를 정의합니다.

MapODataRoute 메서드는 OData 엔드포인트에 대한 경로를 추가합니다.

config.Routes.MapODataRoute("ODataRoute", "odata", model);

첫 번째 매개 변수는 경로의 이름입니다. 서비스의 클라이언트에 이 이름이 표시되지 않습니다. 두 번째 매개 변수는 엔드포인트의 URI 접두사입니다. 이 코드를 고려할 때 Products 엔터티 집합의 URI는 http:// hostname/odata/Products입니다. 애플리케이션에는 둘 이상의 OData 엔드포인트가 있을 수 있습니다. 각 엔드포인트에 대해 MapODataRoute 를 호출하고 고유한 경로 이름과 고유한 URI 접두사를 제공합니다.

데이터베이스 시드(선택 사항)

이 단계에서는 Entity Framework를 사용하여 일부 테스트 데이터로 데이터베이스를 시드합니다. 이 단계는 선택 사항이지만 OData 엔드포인트를 즉시 테스트할 수 있습니다.

도구 메뉴에서 NuGet 패키지 관리자를 선택한 다음 패키지 관리자 콘솔을 선택합니다. 패키지 관리자 콘솔 창에서 다음 명령을 입력합니다.

Enable-Migrations

그러면 Migrations라는 폴더와 Configuration.cs라는 코드 파일이 추가됩니다.

마이그레이션이라는 새로 추가된 폴더를 순환하고 그 안에 파일을 표시하는 솔루션 탐색기의 제품 서비스 메뉴 스크린샷

이 파일을 열고 메서드에 다음 코드를 Configuration.Seed 추가합니다.

protected override void Seed(ProductService.Models.ProductServiceContext context)
{
    // New code 
    context.Products.AddOrUpdate(new Product[] {
        new Product() { ID = 1, Name = "Hat", Price = 15, Category = "Apparel" },
        new Product() { ID = 2, Name = "Socks", Price = 5, Category = "Apparel" },
        new Product() { ID = 3, Name = "Scarf", Price = 12, Category = "Apparel" },
        new Product() { ID = 4, Name = "Yo-yo", Price = 4.95M, Category = "Toys" },
        new Product() { ID = 5, Name = "Puzzle", Price = 8, Category = "Toys" },
    });
}

패키지 관리자 콘솔 창에서 다음 명령을 입력합니다.

Add-Migration Initial
Update-Database

이러한 명령은 데이터베이스를 만든 다음 해당 코드를 실행하는 코드를 생성합니다.

OData 엔드포인트 탐색

이 섹션에서는 Fiddler 웹 디버깅 프록시를 사용하여 엔드포인트에 요청을 보내고 응답 메시지를 검사합니다. 이렇게 하면 OData 엔드포인트의 기능을 이해하는 데 도움이 됩니다.

Visual Studio에서 F5 키를 눌러 디버깅을 시작합니다. 기본적으로 Visual Studio는 브라우저를 http://localhost:*port*로 엽니다. 여기서 포트 는 프로젝트 설정에 구성된 포트 번호입니다.

프로젝트 설정에서 포트 번호를 변경할 수 있습니다. 솔루션 탐색기 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 속성 창에서 을 선택합니다. 프로젝트 URL 아래에 포트 번호를 입력합니다.

서비스 문서

서비스 문서에는 OData 엔드포인트에 대한 엔터티 집합 목록이 포함되어 있습니다. 서비스 문서를 얻으려면 GET 요청을 서비스의 루트 URI로 보냅니다.

Fiddler를 사용하여 작성기http://localhost:port/odata/에 다음 URI를 입력합니다. 여기서 포트는 포트 번호입니다.

'구문 분석' 탭이 선택된 다른 탭을 표시하고 작성기 필드에 U R L 데이터를 표시하는 서비스 문서 창의 스크린샷

실행 단추를 클릭합니다. Fiddler는 HTTP GET 요청을 애플리케이션에 보냅니다. 웹 세션 목록에 응답이 표시됩니다. 모든 것이 작동하면 상태 코드는 200이 됩니다.

결과 번호가 200인 H T T P 프로토콜과 U R L 주소 및 호스트를 보여 주는 웹 세션 목록의 스크린샷

웹 세션 목록에서 응답을 두 번 클릭하여 검사기 탭에서 응답 메시지의 세부 정보를 확인합니다.

요청 헤더 응답 및 X M L 정보를 표시하는 웹 세션 목록의 검사기 탭 스크린샷

원시 HTTP 응답 메시지는 다음과 유사합니다.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/atomsvc+xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 17:51:01 GMT
Content-Length: 364

<?xml version="1.0" encoding="utf-8"?>
<service xml:base="http://localhost:60868/odata" 
    xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
  <workspace>
    <atom:title type="text">Default</atom:title>
    <collection href="Products">
        <atom:title type="text">Products</atom:title>
    </collection>
    </workspace>
</service></pre>

기본적으로 Web API는 서비스 문서를 AtomPub 형식으로 반환합니다. JSON을 요청하려면 HTTP 요청에 다음 헤더를 추가합니다.

Accept: application/json

요청 헤더 섹션에 있는 API의 응답을 보여 주는 웹 세션 창의 스크린샷과 j son 요청을 작성할 위치를 순환합니다.

이제 HTTP 응답에 JSON 페이로드가 포함됩니다.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 22:59:28 GMT
Content-Length: 136

{
  "odata.metadata":"http://localhost:60868/odata/$metadata","value":[
    {
      "name":"Products","url":"Products"
    }
  ]
}

서비스 메타데이터 문서

서비스 메타데이터 문서에서는 CSDL(개념 스키마 정의 언어)이라는 XML 언어를 사용하여 서비스의 데이터 모델을 설명합니다. 메타데이터 문서는 서비스의 데이터 구조를 보여 하며 클라이언트 코드를 생성하는 데 사용할 수 있습니다.

메타데이터 문서를 얻으려면 GET 요청을 로 http://localhost:port/odata/$metadata보냅니다. 다음은 이 자습서에 표시된 엔드포인트에 대한 메타데이터입니다.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:05:52 GMT
Content-Length: 1086

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
  <edmx:DataServices m:DataServiceVersion="3.0" m:MaxDataServiceVersion="3.0" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <Schema Namespace="ProductService.Models" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
      <EntityType Name="Product">
        <Key>
          <PropertyRef Name="ID" />
        </Key>
        <Property Name="ID" Type="Edm.Int32" Nullable="false" />
        <Property Name="Name" Type="Edm.String" />
        <Property Name="Price" Type="Edm.Decimal" Nullable="false" />
        <Property Name="Category" Type="Edm.String" />
      </EntityType>
    </Schema>
    <Schema Namespace="Default" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
      <EntityContainer Name="Container" m:IsDefaultEntityContainer="true">
        <EntitySet Name="Products" EntityType="ProductService.Models.Product" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

엔터티 집합

Products 엔터티 집합을 얻으려면 GET 요청을 에 http://localhost:port/odata/Products보냅니다.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:01:31 GMT
Content-Length: 459

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products","value":[
    {
      "ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
    },{
      "ID":2,"Name":"Socks","Price":"5.00","Category":"Apparel"
    },{
      "ID":3,"Name":"Scarf","Price":"12.00","Category":"Apparel"
    },{
      "ID":4,"Name":"Yo-yo","Price":"4.95","Category":"Toys"
    },{
      "ID":5,"Name":"Puzzle","Price":"8.00","Category":"Toys"
    }
  ]
}

엔터티

개별 제품을 가져오려면 GET 요청을 로 http://localhost:port/odata/Products(1)보냅니다. 여기서 "1"은 제품 ID입니다.

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/json; charset=utf-8
Expires: -1
Server: Microsoft-IIS/8.0
DataServiceVersion: 3.0
Date: Mon, 23 Sep 2013 23:04:29 GMT
Content-Length: 140

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element","ID":1,
      "Name":"Hat","Price":"15.00","Category":"Apparel"
}

OData Serialization 형식

OData는 다음과 같은 여러 serialization 형식을 지원합니다.

  • Atom Pub(XML)
  • JSON "light"(OData v3에 도입됨)
  • JSON "verbose"(OData v2)

기본적으로 Web API는 AtomPubJSON "light" 형식을 사용합니다.

AtomPub 형식을 얻으려면 Accept 헤더를 "application/atom+xml"로 설정합니다. 아래에는 예제 응답 본문이 나와 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://localhost:60868/odata" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
  <id>http://localhost:60868/odata/Products(1)</id>
  <category term="ProductService.Models.Product" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <link rel="edit" href="http://localhost:60868/odata/Products(1)" />
  <link rel="self" href="http://localhost:60868/odata/Products(1)" />
  <title />
  <updated>2013-09-23T23:42:11Z</updated>
  <author>
    <name />
  </author>
  <content type="application/xml">
    <m:properties>
      <d:ID m:type="Edm.Int32">1</d:ID>
      <d:Name>Hat</d:Name>
      <d:Price m:type="Edm.Decimal">15.00</d:Price>
      <d:Category>Apparel</d:Category>
    </m:properties>
  </content>
</entry>

Atom 형식의 한 가지 명백한 단점을 볼 수 있습니다. JSON 조명보다 훨씬 더 자세한 정보입니다. 그러나 AtomPub를 이해하는 클라이언트가 있는 경우 클라이언트는 JSON보다 해당 형식을 선호할 수 있습니다.

동일한 엔터티의 JSON 라이트 버전은 다음과 같습니다.

{
  "odata.metadata":"http://localhost:60868/odata/$metadata#Products/@Element",
  "ID":1,
  "Name":"Hat",
  "Price":"15.00",
  "Category":"Apparel"
}

JSON 라이트 형식은 OData 프로토콜 버전 3에서 도입되었습니다. 이전 버전과의 호환성을 위해 클라이언트는 이전의 "자세한 정보 표시" JSON 형식을 요청할 수 있습니다. 자세한 JSON을 요청하려면 Accept 헤더를 로 application/json;odata=verbose설정합니다. 자세한 내용은 다음과 같습니다.

{
  "d":{
    "__metadata":{
      "id":"http://localhost:18285/odata/Products(1)",
      "uri":"http://localhost:18285/odata/Products(1)",
      "type":"ProductService.Models.Product"
    },"ID":1,"Name":"Hat","Price":"15.00","Category":"Apparel"
  }
}

이 형식은 응답 본문에 더 많은 메타데이터를 전달하므로 전체 세션에 상당한 오버헤드를 추가할 수 있습니다. 또한 개체를 "d"라는 속성에 래핑하여 간접 참조 수준을 추가합니다.

다음 단계