ASP.NET Web API 2 Odata'da Yönlendirme Kuralları

Bu makalede, ASP.NET 4.x'teki Web API 2'nin OData uç noktaları için kullandığı yönlendirme kuralları açıklanmaktadır.

Web API'si bir OData isteği aldığında, isteği bir denetleyici adı ve bir eylem adıyla eşler. Eşleme HTTP yöntemini ve URI'yi temel alır. Örneğin, GET /odata/Products(1) ile ProductsController.GetProducteşler.

Bu makalenin 1. bölümünde, yerleşik OData yönlendirme kurallarını açıkliyorum. Bu kurallar OData uç noktaları için özel olarak tasarlanmıştır ve varsayılan Web API yönlendirme sisteminin yerini alır. ( MapODataRoute'u çağırdığınızda değiştirme gerçekleşir.)

2. bölümde özel yönlendirme kurallarının nasıl ekleneceğini gösteriyorum. Şu anda yerleşik kurallar tüm OData URI'lerini kapsamaz, ancak bunları ek durumları işleyecek şekilde genişletebilirsiniz.

Yerleşik Yönlendirme Kuralları

Web API'sinde OData yönlendirme kurallarını açıklamadan önce OData URI'lerini anlamak yararlı olacaktır. OData URI'leri şunlardan oluşur:

  • Hizmet kökü
  • Kaynak yolu
  • Sorgu seçenekleri

Hizmet kökünü, kaynak yolunu ve sorgu seçeneklerini soldan sağa görüntüleyerek O Veri yönlendirme kurallarının nasıl göründüğünü gösteren ekran görüntüsü.

Yönlendirme için önemli olan kaynak yoludur. Kaynak yolu segmentlere ayrılır. Örneğin, /Products(1)/Supplier üç segmenti vardır:

  • Products "Products" adlı bir varlık kümesini ifade eder.
  • 1 , kümeden tek bir varlık seçen bir varlık anahtarıdır.
  • Supplier ilgili varlığı seçen bir gezinti özelliğidir.

Bu yol, ürün 1'in tedarikçisini seçer.

Not

OData yol kesimleri her zaman URI segmentlerine karşılık gelir. Örneğin, "1" bir yol kesimi olarak kabul edilir.

Denetleyici Adları. Denetleyici adı her zaman kaynak yolunun kökündeki varlık kümesinden türetilir. Örneğin, kaynak yolu ise /Products(1)/Supplier, Web API'si adlı ProductsControllerbir denetleyici arar.

Eylem Adları. Eylem adları, aşağıdaki tablolarda listelendiği gibi yol segmentlerinden ve varlık veri modelinden (EDM) türetilir. Bazı durumlarda eylem adı için iki seçeneğiniz vardır. Örneğin, "Get" veya "GetProducts".

Varlıkları Sorgulama

İstek Örnek URI Eylem Adı Örnek Eylem
GET /entityset /Ürünler GetEntitySet veya Get GetProducts
GET /entityset(anahtar) /Products(1) GetEntityType veya Get GetProduct
GET /entityset(key)/cast /Products(1)/Models.Book GetEntityType veya Get GetBook

Daha fazla bilgi için bkz. Read-Only OData Uç Noktası Oluşturma.

Varlıkları Oluşturma, Güncelleştirme ve Silme

İstek Örnek URI Eylem Adı Örnek Eylem
POST /entityset /Ürünler PostEntityType veya Post PostProduct
PUT /entityset(anahtar) /Products(1) PutEntityType veya Put PutProduct
PUT /entityset(key)/cast /Products(1)/Models.Book PutEntityType veya Put PutBook
PATCH /entityset(anahtar) /Products(1) PatchEntityType veya Patch PatchProduct
PATCH /entityset(key)/cast /Products(1)/Models.Book PatchEntityType veya Patch PatchBook
DELETE /entityset(anahtar) /Products(1) DeleteEntityType veya Delete DeleteProduct
DELETE /entityset(key)/cast /Products(1)/Models.Book DeleteEntityType veya Delete DeleteBook

Gezinti Özelliğini Sorgulama

İstek Örnek URI Eylem Adı Örnek Eylem
GET /entityset(key)/navigation /Products(1)/Supplier GetNavigationFromEntityType veya GetNavigation GetSupplierFromProduct
GET /entityset(key)/cast/navigation /Products(1)/Models.Book/Author GetNavigationFromEntityType veya GetNavigation GetAuthorFromBook

Daha fazla bilgi için bkz . Varlık İlişkileriyle Çalışma.

Bağlantıları Oluşturma ve Silme

İstek Örnek URI Eylem Adı
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

Daha fazla bilgi için bkz . Varlık İlişkileriyle Çalışma.

Özellikler

Web API 2 gerektirir

İstek Örnek URI Eylem Adı Örnek Eylem
GET /entityset(key)/property /Products(1)/Name GetPropertyFromEntityType veya GetProperty GetNameFromProduct
GET /entityset(key)/cast/property /Products(1)/Models.Book/Author GetPropertyFromEntityType veya GetProperty GetTitleFromBook

Eylemler

İstek Örnek URI Eylem Adı Örnek Eylem
POST /entityset(key)/action /Products(1)/Rate ActionNameOnEntityType veya ActionName RateOnProduct
POST /entityset(key)/cast/action /Products(1)/Models.Book/CheckOut ActionNameOnEntityType veya ActionName CheckOutOnBook

Daha fazla bilgi için bkz. OData Eylemleri.

Yöntem İmzaları

Yöntem imzaları için bazı kurallar şunlardır:

  • Yol bir anahtar içeriyorsa, eylemin key adlı bir parametresi olmalıdır.
  • Yol bir gezinti özelliğine anahtar içeriyorsa, eylemin relatedKey adlı bir parametresi olmalıdır.
  • Key ve relatedKey parametrelerini [FromODataUri] parametresiyle süsleyin.
  • POST ve PUT istekleri, varlık türünün bir parametresini alır.
  • PATCH istekleri Delta<T> türünde bir parametre alır ve burada T , varlık türüdür.

Başvuru için, her yerleşik OData yönlendirme kuralı için yöntem imzalarını gösteren bir örnek aşağıda verilmiştir.

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

Özel Yönlendirme Kuralları

Şu anda yerleşik kurallar tüm olası OData URI'lerini kapsamaz. IODataRoutingConvention arabirimini uygulayarak yeni kurallar ekleyebilirsiniz. Bu arabirimin iki yöntemi vardır:

string SelectController(ODataPath odataPath, HttpRequestMessage request);
string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, 
    ILookup<string, HttpActionDescriptor> actionMap);
  • SelectController denetleyicinin adını döndürür.
  • SelectAction eylemin adını döndürür.

Her iki yöntem için de kural bu istek için geçerli değilse yöntemin null döndürmesi gerekir.

ODataPath parametresi ayrıştırılmış OData kaynak yolunu temsil eder. Kaynak yolunun her kesimi için bir tane olmak üzere ODataPathSegment örneklerinin listesini içerir. ODataPathSegment soyut bir sınıftır; her segment türü, ODataPathSegment'ten türetilen bir sınıfla temsil edilir.

ODataPath.TemplatePath özelliği, yol kesimlerinin tümünü birleştirmeyi temsil eden bir dizedir. Örneğin, URI ise /Products(1)/Supplieryol şablonu "~/entityset/key/navigation" şeklindedir. Segmentlerin doğrudan URI segmentlerine karşılık gelmez. Örneğin, varlık anahtarı (1) kendi ODataPathSegment'i olarak temsil edilir.

Genellikle, IODataRoutingConvention uygulaması aşağıdakileri yapar:

  1. Bu kuralın geçerli istek için geçerli olup olmadığını görmek için yol şablonunu karşılaştırın. Geçerli değilse null döndür.
  2. Kural geçerliyse, denetleyici ve eylem adlarını türetmek için ODataPathSegment örneklerinin özelliklerini kullanın.
  3. Eylemler için, yol sözlüğüne eylem parametrelerine (genellikle varlık anahtarları) bağlanması gereken tüm değerleri ekleyin.

Şimdi belirli bir örneğe bakalım. Yerleşik yönlendirme kuralları, bir gezinti koleksiyonunda dizin oluşturmayı desteklemez. Başka bir deyişle, URI'ler için aşağıdaki gibi bir kural yoktur:

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

Burada, bu tür bir sorguyu işlemek için özel bir yönlendirme kuralı yer alır.

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

Notlar:

  1. Bu sınıftaki SelectController yöntemi bu yeni yönlendirme kuralı için uygun olduğundan EntitySetRoutingConvention'dan türetiyorum. Bu, SelectController'ı yeniden uygulamam gerekmeyecek anlamına gelir.
  2. Kural yalnızca GET istekleri için ve yalnızca yol şablonu "~/entityset/key/navigation/key" olduğunda geçerlidir.
  3. Eylem adı "Get{EntityType}" şeklindedir; burada {EntityType} , gezinti koleksiyonunun türüdür. Örneğin, "GetSupplier". İstediğiniz adlandırma kuralını kullanabilirsiniz; denetleyici eylemlerinizin eşleştiğinden emin olmanız gerekir.
  4. Eylem , key ve relatedKey adlı iki parametre alır. (Önceden tanımlanmış bazı parametre adlarının listesi için bkz . ODataRouteConstants.)

Sonraki adım, yeni kuralı yönlendirme kuralları listesine eklemektir. Bu, aşağıdaki kodda gösterildiği gibi yapılandırma sırasında gerçekleşir:

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

        }
    }
}

Aşağıda, incelenecek diğer örnek yönlendirme kuralları verilmiştir:

Web API'sinin kendisi de açık kaynak olduğundan, yerleşik yönlendirme kurallarının kaynak kodunu görebilirsiniz. Bunlar System.Web.Http.OData.Routing.Conventions ad alanında tanımlanır.