다음을 통해 공유


ASP.NET Web API 2 Odata의 라우팅 규칙

이 문서에서는 ASP.NET 4.x의 Web API 2가 OData 엔드포인트에 사용하는 라우팅 규칙에 대해 설명합니다.

Web API는 OData 요청을 받으면 요청을 컨트롤러 이름 및 작업 이름에 매핑합니다. 매핑은 HTTP 메서드 및 URI를 기반으로 합니다. 예를 들어 는 GET /odata/Products(1)ProductsController.GetProduct매핑합니다.

이 문서의 1부에서는 기본 제공 OData 라우팅 규칙에 대해 설명합니다. 이러한 규칙은 OData 엔드포인트용으로 특별히 설계되었으며 기본 Web API 라우팅 시스템을 대체합니다. ( MapODataRoute를 호출할 때 대체가 수행됩니다.)

2부에서는 사용자 지정 라우팅 규칙을 추가하는 방법을 보여 줍니다. 현재 기본 제공 규칙은 OData URI의 전체 범위를 다루지 않지만 추가 사례를 처리하도록 확장할 수 있습니다.

기본 제공 라우팅 규칙

Web API에서 OData 라우팅 규칙을 설명하기 전에 OData URI를 이해하는 것이 유용합니다. OData URI는 다음으로 구성됩니다.

  • 서비스 루트
  • 리소스 경로
  • 쿼리 옵션

왼쪽에서 오른쪽으로 서비스 루트, 리소스 경로 및 쿼리 옵션을 표시하는 O 데이터 라우팅 규칙의 모양을 보여주는 스크린샷

라우팅의 경우 중요한 부분은 리소스 경로입니다. 리소스 경로는 세그먼트로 나뉩니다. 예를 들어 /Products(1)/Supplier 에는 세 개의 세그먼트가 있습니다.

  • Products 는 "Products"라는 엔터티 집합을 나타냅니다.
  • 1 는 집합에서 단일 엔터티를 선택하는 엔터티 키입니다.
  • Supplier 는 관련 엔터티를 선택하는 탐색 속성입니다.

따라서 이 경로는 제품 1의 공급업체를 선택합니다.

참고

OData 경로 세그먼트가 항상 URI 세그먼트에 해당하지는 않습니다. 예를 들어 "1"은 경로 세그먼트로 간주됩니다.

컨트롤러 이름입니다. 컨트롤러 이름은 항상 리소스 경로의 루트에 있는 엔터티 집합에서 파생됩니다. 예를 들어 리소스 경로가 인 경우 Web API는 /Products(1)/Supplier라는 ProductsController컨트롤러를 찾습니다.

작업 이름입니다. 작업 이름은 다음 표에 나열된 대로 경로 세그먼트와 EDM(엔터티 데이터 모델)에서 파생됩니다. 경우에 따라 작업 이름에 대해 두 가지 선택 사항이 있습니다. 예를 들어 "Get" 또는 "GetProducts"입니다.

엔터티 쿼리

요청 예제 URI 동작 이름 예제 작업
GET /entityset /제품 GetEntitySet 또는 Get GetProducts
GET /entityset(key) /Products(1) GetEntityType 또는 Get GetProduct
GET /entityset(key)/cast /Products(1)/Models.Book GetEntityType 또는 Get GetBook

자세한 내용은 Read-Only OData 엔드포인트 만들기를 참조하세요.

엔터티 만들기, 업데이트 및 삭제

요청 예제 URI 동작 이름 예제 작업
POST /entityset /제품 PostEntityType 또는 Post PostProduct
PUT /entityset(key) /Products(1) PutEntityType 또는 Put PutProduct
PUT /entityset(key)/cast /Products(1)/Models.Book PutEntityType 또는 Put PutBook
PATCH /entityset(key) /Products(1) PatchEntityType 또는 패치 PatchProduct
PATCH /entityset(key)/cast /Products(1)/Models.Book PatchEntityType 또는 패치 PatchBook
DELETE /entityset(key) /Products(1) DeleteEntityType 또는 삭제 DeleteProduct
DELETE /entityset(key)/cast /Products(1)/Models.Book DeleteEntityType 또는 삭제 DeleteBook

탐색 속성 쿼리

요청 예제 URI 동작 이름 예제 작업
GET /entityset(key)/navigation /Products(1)/Supplier GetNavigationFromEntityType 또는 GetNavigation GetSupplierFromProduct
GET /entityset(key)/cast/navigation /Products(1)/Models.Book/Author GetNavigationFromEntityType 또는 GetNavigation GetAuthorFromBook

자세한 내용은 엔터티 관계 작업을 참조하세요.

링크 만들기 및 삭제

요청 예제 URI 동작 이름
POST /entityset(key)/$links/navigation /Products(1)/$links/Supplier CreateLink
PUT /entityset(key)/$links/navigation /Products(1)/$links/Supplier CreateLink
DELETE /entityset(key)/$links/navigation /Products(1)/$links/Supplier DeleteLink
DELETE /entityset(key)/$links/navigation(relatedKey) /products/(1)/$links/Suppliers(1) DeleteLink

자세한 내용은 엔터티 관계 작업을 참조하세요.

속성

Web API 2 필요

요청 예제 URI 동작 이름 예제 작업
GET /entityset(key)/property /Products(1)/Name GetPropertyFromEntityType 또는 GetProperty GetNameFromProduct
GET /entityset(key)/cast/property /Products(1)/Models.Book/Author GetPropertyFromEntityType 또는 GetProperty GetTitleFromBook

actions

요청 예제 URI 동작 이름 예제 작업
POST /entityset(key)/action /Products(1)/Rate ActionNameOnEntityType 또는 ActionName RateOnProduct
POST /entityset(key)/cast/action /Products(1)/Models.Book/CheckOut ActionNameOnEntityType 또는 ActionName CheckOutOnBook

자세한 내용은 OData Actions를 참조하세요.

메서드 서명

다음은 메서드 서명에 대한 몇 가지 규칙입니다.

  • 경로에 키가 포함된 경우 작업에는 라는 매개 변수가 있어야 합니다.
  • 경로에 탐색 속성에 키가 포함된 경우 작업에 relatedKey라는 매개 변수가 있어야 합니다.
  • [FromODataUri] 매개 변수를 사용하여 relatedKey 매개 변수를 데코레이트합니다.
  • POST 및 PUT 요청은 엔터티 형식의 매개 변수를 사용합니다.
  • PATCH 요청은 Delta<T> 형식의 매개 변수를 사용합니다. 여기서 T 는 엔터티 형식입니다.

참고로, 모든 기본 제공 OData 라우팅 규칙에 대한 메서드 서명을 보여 주는 예제는 다음과 같습니다.

public class ProductsController : ODataController
{
    // GET /odata/Products
    public IQueryable<Product> Get()

    // GET /odata/Products(1)
    public Product Get([FromODataUri] int key)

    // GET /odata/Products(1)/ODataRouting.Models.Book
    public Book GetBook([FromODataUri] int key)

    // POST /odata/Products 
    public HttpResponseMessage Post(Product item)

    // PUT /odata/Products(1)
    public HttpResponseMessage Put([FromODataUri] int key, Product item)

    // PATCH /odata/Products(1)
    public HttpResponseMessage Patch([FromODataUri] int key, Delta<Product> item)

    // DELETE /odata/Products(1)
    public HttpResponseMessage Delete([FromODataUri] int key)

    // PUT /odata/Products(1)/ODataRouting.Models.Book
    public HttpResponseMessage PutBook([FromODataUri] int key, Book item)

    // PATCH /odata/Products(1)/ODataRouting.Models.Book
    public HttpResponseMessage PatchBook([FromODataUri] int key, Delta<Book> item)

    // DELETE /odata/Products(1)/ODataRouting.Models.Book
    public HttpResponseMessage DeleteBook([FromODataUri] int key)

    //  GET /odata/Products(1)/Supplier
    public Supplier GetSupplierFromProduct([FromODataUri] int key)

    // GET /odata/Products(1)/ODataRouting.Models.Book/Author
    public Author GetAuthorFromBook([FromODataUri] int key)

    // POST /odata/Products(1)/$links/Supplier
    public HttpResponseMessage CreateLink([FromODataUri] int key, 
        string navigationProperty, [FromBody] Uri link)

    // DELETE /odata/Products(1)/$links/Supplier
    public HttpResponseMessage DeleteLink([FromODataUri] int key, 
        string navigationProperty, [FromBody] Uri link)

    // DELETE /odata/Products(1)/$links/Parts(1)
    public HttpResponseMessage DeleteLink([FromODataUri] int key, string relatedKey, string navigationProperty)

    // GET odata/Products(1)/Name
    // GET odata/Products(1)/Name/$value
    public HttpResponseMessage GetNameFromProduct([FromODataUri] int key)

    // GET /odata/Products(1)/ODataRouting.Models.Book/Title
    // GET /odata/Products(1)/ODataRouting.Models.Book/Title/$value
    public HttpResponseMessage GetTitleFromBook([FromODataUri] int key)
}

사용자 지정 라우팅 규칙

현재 기본 제공 규칙은 가능한 모든 OData URI를 다루지 않습니다. IODataRoutingConvention 인터페이스를 구현하여 새 규칙을 추가할 수 있습니다. 이 인터페이스에는 두 가지 메서드가 있습니다.

string SelectController(ODataPath odataPath, HttpRequestMessage request);
string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, 
    ILookup<string, HttpActionDescriptor> actionMap);
  • SelectController 는 컨트롤러의 이름을 반환합니다.
  • SelectAction 은 작업의 이름을 반환합니다.

두 메서드 모두 규칙이 해당 요청에 적용되지 않으면 메서드는 null을 반환해야 합니다.

ODataPath 매개 변수는 구문 분석된 OData 리소스 경로를 나타냅니다. 여기에는 리소스 경로의 각 세그먼트에 대해 하나씩 ODataPathSegment 인스턴스 목록이 포함되어 있습니다. ODataPathSegment 는 추상 클래스입니다. 각 세그먼트 형식은 ODataPathSegment에서 파생되는 클래스로 표시됩니다.

ODataPath.TemplatePath 속성은 모든 경로 세그먼트의 연결을 나타내는 문자열입니다. 예를 들어 URI가 /Products(1)/Supplier인 경우 경로 템플릿은 "~/entityset/key/navigation"입니다. 세그먼트는 URI 세그먼트에 직접 해당하지 않습니다. 예를 들어 엔터티 키(1)는 자체 ODataPathSegment로 표시됩니다.

일반적으로 IODataRoutingConvention 의 구현은 다음을 수행합니다.

  1. 경로 템플릿을 비교하여 이 규칙이 현재 요청에 적용되는지 확인합니다. 적용되지 않으면 null을 반환합니다.
  2. 규칙이 적용되는 경우 ODataPathSegment 인스턴스의 속성을 사용하여 컨트롤러 및 작업 이름을 파생합니다.
  3. 작업의 경우 작업 매개 변수(일반적으로 엔터티 키)에 바인딩해야 하는 모든 값을 경로 사전에 추가합니다.

특정 예제를 살펴보겠습니다. 기본 제공 라우팅 규칙은 탐색 컬렉션에 대한 인덱싱을 지원하지 않습니다. 즉, 다음과 같은 URI에 대한 규칙은 없습니다.

/odata/Products(1)/Suppliers(1)

다음은 이러한 유형의 쿼리를 처리하는 사용자 지정 라우팅 규칙입니다.

using Microsoft.Data.Edm;
using System.Linq;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;

namespace ODataRouting
{
    public class NavigationIndexRoutingConvention : EntitySetRoutingConvention
    {
        public override string SelectAction(ODataPath odataPath, HttpControllerContext context, 
            ILookup<string, HttpActionDescriptor> actionMap)
        {
            if (context.Request.Method == HttpMethod.Get && 
                odataPath.PathTemplate == "~/entityset/key/navigation/key")
            {
                NavigationPathSegment navigationSegment = odataPath.Segments[2] as NavigationPathSegment;
                IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty.Partner;
                IEdmEntityType declaringType = navigationProperty.DeclaringType as IEdmEntityType;

                string actionName = "Get" + declaringType.Name;
                if (actionMap.Contains(actionName))
                {
                    // Add keys to route data, so they will bind to action parameters.
                    KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
                    context.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;

                    KeyValuePathSegment relatedKeySegment = odataPath.Segments[3] as KeyValuePathSegment;
                    context.RouteData.Values[ODataRouteConstants.RelatedKey] = relatedKeySegment.Value;

                    return actionName;
                }
            }
            // Not a match.
            return null;
        }
    }
}

참고:

  1. 해당 클래스의 SelectController 메서드가 이 새 라우팅 규칙에 적합하기 때문에 EntitySetRoutingConvention에서 파생됩니다. 즉 , SelectController를 다시 구현할 필요가 없습니다.
  2. 규칙은 GET 요청에만 적용되며 경로 템플릿이 "~/entityset/key/navigation/key"인 경우에만 적용됩니다.
  3. 작업 이름은 "Get{EntityType}"입니다. 여기서 {EntityType} 은 탐색 컬렉션의 형식입니다. 예를 들어 "GetSupplier"입니다. 원하는 명명 규칙을 사용할 수 있습니다. 컨트롤러 작업이 일치하는지 확인합니다.
  4. 이 작업은 keyrelatedKey라는 두 개의 매개 변수를 사용합니다. 미리 정의된 일부 매개 변수 이름 목록은 ODataRouteConstants를 참조하세요.

다음 단계는 라우팅 규칙 목록에 새 규칙을 추가하는 것입니다. 이 문제는 다음 코드와 같이 구성 중에 발생합니다.

using ODataRouting.Models;
using System.Web.Http;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Routing;
using System.Web.Http.OData.Routing.Conventions;

namespace ODataRouting
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
            // Create EDM (not shown).

            // Create the default collection of built-in conventions.
            var conventions = ODataRoutingConventions.CreateDefault();
            // Insert the custom convention at the start of the collection.
            conventions.Insert(0, new NavigationIndexRoutingConvention());

            config.Routes.MapODataRoute(routeName: "ODataRoute",
                routePrefix: "odata",
                model: modelBuilder.GetEdmModel(),
                pathHandler: new DefaultODataPathHandler(),
                routingConventions: conventions);

        }
    }
}

다음은 학습에 유용한 몇 가지 다른 샘플 라우팅 규칙입니다.

물론 Web API 자체는 오픈 소스이므로 기본 제공 라우팅 규칙에 대한 소스 코드를 볼 수 있습니다. 이는 System.Web.Http.OData.Routing.Conventions 네임스페이스에 정의되어 있습니다 .