다음을 통해 공유


ASP.NET Web API 사용하여 OData v4 엔드포인트 만들기

OData(Open Data Protocol)는 웹용 데이터 액세스 프로토콜입니다. OData는 CRUD 작업(만들기, 읽기, 업데이트 및 삭제)을 통해 데이터 집합을 쿼리하고 조작하는 균일한 방법을 제공합니다.

ASP.NET Web API 프로토콜의 v3 및 v4를 모두 지원합니다. v3 엔드포인트와 나란히 실행되는 v4 엔드포인트를 가질 수도 있습니다.

이 자습서에서는 CRUD 작업을 지원하는 OData v4 엔드포인트를 만드는 방법을 보여 줍니다.

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

  • Web API 5.2
  • OData v4
  • Visual Studio 2017( 여기에서 Visual Studio 2017 다운로드)
  • Entity Framework 6
  • .NET 4.7.2

자습서 버전

OData 버전 3의 경우 OData v3 엔드포인트 만들기를 참조하세요.

Visual Studio 프로젝트 만들기

Visual Studio의 파일 메뉴에서 >프로젝트를 선택합니다.

설치된Visual C#>Web> 확장하고 ASP.NET 웹 애플리케이션(.NET Framework) 템플릿을 선택합니다. 프로젝트 이름을 "ProductService"로 지정합니다.

점 NET Framework를 사용하여 ASP dot NET 웹 애플리케이션을 만드는 메뉴 옵션을 보여 주는 Visual Studio 새 프로젝트 창의 스크린샷.

확인을 선택합니다.

웹 A P I 폴더 및 핵심 참조를 사용하여 애플리케이션을 만드는 데 사용할 수 있는 템플릿을 보여 주는 A SP dot NET 웹 애플리케이션의 스크린샷.

비어 있는 템플릿을 선택합니다. 에 대한 폴더 및 핵심 참조 추가에서 Web API를 선택합니다. 확인을 선택합니다.

OData 패키지 설치

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

Install-Package Microsoft.AspNet.Odata

이 명령은 최신 OData NuGet 패키지를 설치합니다.

모델 클래스 추가

모델은 애플리케이션의 데이터 엔터티를 나타내는 개체입니다.

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

프로젝트에 모델 클래스 개체를 추가하는 경로를 강조 표시하는 솔루션 탐색기 창의 스크린샷

참고

규칙에 따라 모델 클래스는 Models 폴더에 배치되지만 자체 프로젝트에서 이 규칙을 따를 필요는 없습니다.

클래스 Product 이름을 지정합니다. Product.cs 파일에서 상용구 코드를 다음으로 바꿉니다.

namespace ProductService.Models
{
    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가 5인 제품을 가져오려면 URI는 입니다 /Products(5). 속성은 Id 백 엔드 데이터베이스의 기본 키이기도 합니다.

Entity Framework 사용

이 자습서에서는 EF(Entity Framework) Code First를 사용하여 백 엔드 데이터베이스를 만듭니다.

참고

Web API OData에는 EF가 필요하지 않습니다. 데이터베이스 엔터티를 모델로 변환할 수 있는 데이터 액세스 계층을 사용합니다.

먼저 EF용 NuGet 패키지를 설치합니다. 도구 메뉴에서 NuGet 패키지 관리자>패키지 관리자 콘솔을 선택합니다. 패키지 관리자 콘솔 창에서 다음을 입력합니다.

Install-Package EntityFramework

Web.config 파일을 열고 configSections 요소 다음에 구성 요소 내에 다음 섹션을 추가합니다.

<configuration>
  <configSections>
    <!-- ... -->
  </configSections>

  <!-- Add this: -->
  <connectionStrings>
    <add name="ProductsContext" connectionString="Data Source=(localdb)\mssqllocaldb; 
        Initial Catalog=ProductsContext; Integrated Security=True; MultipleActiveResultSets=True; 
        AttachDbFilename=|DataDirectory|ProductsContext.mdf"
      providerName="System.Data.SqlClient" />
  </connectionStrings>

이 설정은 LocalDB 데이터베이스에 대한 연결 문자열을 추가합니다. 이 데이터베이스는 앱을 로컬로 실행할 때 사용됩니다.

다음으로 Models 폴더에 라는 ProductsContext 클래스를 추가합니다.

using System.Data.Entity;
namespace ProductService.Models
{
    public class ProductsContext : DbContext
    {
        public ProductsContext() 
                : base("name=ProductsContext")
        {
        }
        public DbSet<Product> Products { get; set; }
    }
}

생성자 "name=ProductsContext" 에서 은 연결 문자열의 이름을 지정합니다.

OData 엔드포인트 구성

파일 App_Start/WebApiConfig.cs를 엽니다. 다음 using 문을 추가합니다.

using ProductService.Models;
using Microsoft.AspNet.OData.Builder;
using Microsoft.AspNet.OData.Extensions;

그런 다음 Register 메서드에 다음 코드를 추가합니다.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // New code:
        ODataModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Product>("Products");
        config.MapODataServiceRoute(
            routeName: "ODataRoute",
            routePrefix: null,
            model: builder.GetEdmModel());
    }
}

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

  • EDM(엔터티 데이터 모델)을 만듭니다.
  • 경로를 추가합니다.

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

경로는 HTTP 요청을 엔드포인트로 라우팅하는 방법을 Web API에 알려줍니다. OData v4 경로를 만들려면 MapODataServiceRoute 확장 메서드를 호출합니다.

애플리케이션에 여러 OData 엔드포인트가 있는 경우 각각에 대해 별도의 경로를 만듭니다. 각 경로에 고유한 경로 이름 및 접두사를 지정합니다.

OData 컨트롤러 추가

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

솔루션 탐색기 Controllers 폴더를 마우스 오른쪽 단추로 클릭하고클래스추가>를 선택합니다. 클래스 ProductsController 이름을 지정합니다.

참고

OData v3용 이 자습서 버전에서는 컨트롤러 추가 스캐폴딩을 사용합니다. 현재 OData v4에 대한 스캐폴딩이 없습니다.

ProductsController.cs의 상용구 코드를 다음으로 바꿉니다.

using ProductService.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
namespace ProductService.Controllers
{
    public class ProductsController : ODataController
    {
        ProductsContext db = new ProductsContext();
        private bool ProductExists(int key)
        {
            return db.Products.Any(p => p.Id == key);
        } 
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}

컨트롤러는 클래스를 ProductsContext 사용하여 EF를 사용하여 데이터베이스에 액세스합니다. 컨트롤러는 Dispose 메서드를 재정의하여 ProductsContext를 삭제합니다.

컨트롤러의 시작점입니다. 다음으로 모든 CRUD 작업에 대한 메서드를 추가합니다.

엔터티 집합 쿼리

에 다음 메서드를 추가합니다 ProductsController.

[EnableQuery]
public IQueryable<Product> Get()
{
    return db.Products;
}
[EnableQuery]
public SingleResult<Product> Get([FromODataUri] int key)
{
    IQueryable<Product> result = db.Products.Where(p => p.Id == key);
    return SingleResult.Create(result);
}

매개 변수가 없는 버전의 Get 메서드는 전체 Products 컬렉션을 반환합니다. 매개 변수가 있는 메서드는 Get 키로 제품을 조회합니다(이 경우 Id 속성).

[EnableQuery] 특성을 사용하면 클라이언트가 $filter, $sort 및 $page 같은 쿼리 옵션을 사용하여 쿼리를 수정할 수 있습니다. 자세한 내용은 OData 쿼리 옵션 지원을 참조하세요.

엔터티 집합에 엔터티 추가

클라이언트가 데이터베이스에 새 제품을 추가할 수 있도록 하려면 다음 메서드를 에 추가합니다 ProductsController.

public async Task<IHttpActionResult> Post(Product product)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    db.Products.Add(product);
    await db.SaveChangesAsync();
    return Created(product);
}

엔터티 업데이트

OData는 엔터티 PATCH 및 PUT을 업데이트하기 위한 두 가지 의미 체계를 지원합니다.

  • PATCH는 부분 업데이트를 수행합니다. 클라이언트는 업데이트할 속성만 지정합니다.
  • PUT은 전체 엔터티를 대체합니다.

PUT의 단점은 클라이언트가 변경되지 않는 값을 포함하여 엔터티의 모든 속성에 대한 값을 보내야 한다는 것입니다. OData 사양은 PATCH가 선호됨을 표시합니다.

어쨌든 PATCH 및 PUT 메서드 모두에 대한 코드는 다음과 같습니다.

public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    var entity = await db.Products.FindAsync(key);
    if (entity == null)
    {
        return NotFound();
    }
    product.Patch(entity);
    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!ProductExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return Updated(entity);
}
public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    if (key != update.Id)
    {
        return BadRequest();
    }
    db.Entry(update).State = EntityState.Modified;
    try
    {
        await db.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!ProductExists(key))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }
    return Updated(update);
}

PATCH의 경우 컨트롤러는 Delta<T> 형식을 사용하여 변경 내용을 추적합니다.

엔터티 삭제

클라이언트가 데이터베이스에서 제품을 삭제할 수 있도록 하려면 다음 메서드를 에 추가합니다 ProductsController.

public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
    var product = await db.Products.FindAsync(key);
    if (product == null)
    {
        return NotFound();
    }
    db.Products.Remove(product);
    await db.SaveChangesAsync();
    return StatusCode(HttpStatusCode.NoContent);
}