Aracılığıyla paylaş


Bir .NET İstemcisinden OData Hizmetine Çağrı Yapma (C#)

tarafından Mike Wasson

Tamamlanan Projeyi İndir

Bu öğreticide, bir C# istemci uygulamasından OData hizmetinin nasıl çağrılacakları gösterilmektedir.

Öğreticide kullanılan yazılım sürümleri

Bu öğreticide, OData hizmetini çağıran bir istemci uygulaması oluşturma adımlarını inceleyeceğiz. OData hizmeti aşağıdaki varlıkları kullanıma sunar:

  • Product
  • Supplier
  • ProductRating

O Veri hizmeti varlıklarını ve özelliklerinin listesini gösteren diyagram; her birinin nasıl ilişkili olduğunu veya birlikte çalıştığını göstermek için bağlantı okları.

Aşağıdaki makalelerde, Web API'sinde OData hizmetinin nasıl uygulandığı açıklanmaktadır. (Ancak bu öğreticiyi anlamak için bunları okumanız gerekmez.)

Hizmet Ara Sunucusunu Oluşturma

İlk adım bir hizmet ara sunucusu oluşturmaktır. Hizmet ara sunucusu, OData hizmetine erişme yöntemlerini tanımlayan bir .NET sınıfıdır. Proxy, yöntem çağrılarını HTTP isteklerine çevirir.

Hizmet proxy'sinin H T T P istek çağrılarının uygulamadan, hizmet ara sunucusu aracılığıyla ve O Veri hizmetine gidip gelen çağrılarını gösteren diyagram.

Visual Studio'da OData hizmet projesini açarak başlayın. hizmeti IIS Express yerel olarak çalıştırmak için CTRL+F5 tuşlarına basın. Visual Studio tarafından atanan bağlantı noktası numarası da dahil olmak üzere yerel adresi not edin. Ara sunucuyu oluştururken bu adrese ihtiyacınız olacaktır.

Ardından, Visual Studio'nun başka bir örneğini açın ve bir konsol uygulaması projesi oluşturun. Konsol uygulaması OData istemci uygulamamız olacaktır. (Projeyi hizmetle aynı çözüme de ekleyebilirsiniz.)

Not

Kalan adımlar konsol projesine başvurur.

Çözüm Gezgini'da Başvurular'a sağ tıklayın ve Hizmet Başvurusu Ekle'yi seçin.

Yeni bir hizmet başvurusu eklemek için 'başvurular' altındaki menüyü gösteren çözüm gezgini penceresinin ekran görüntüsü.

Hizmet Başvurusu Ekle iletişim kutusunda OData hizmetinin adresini yazın:

http://localhost:port/odata

burada bağlantı noktası , bağlantı noktası numarasıdır.

U R L adresi alanındaki bağlantı noktası numarasını ve Ad alanı eklemek için bir alanı gösteren 'hizmet başvurusu ekle' penceresinin ekran görüntüsü.

Ad alanı için "ProductService" yazın. Bu seçenek proxy sınıfının ad alanını tanımlar.

Git'e tıklayın. Visual Studio, hizmetteki varlıkları bulmak için OData meta veri belgesini okur.

Kapsayıcı hizmetinde çalışan işlemleri göstermek için kapsayıcı hizmetini vurgulayan 'hizmet başvurusu ekle' iletişim kutusunun ekran görüntüsü.

Proxy sınıfını projenize eklemek için Tamam'a tıklayın.

'Ürün hizmeti istemcisi' altındaki menüyü gösteren ve 'Ürün Hizmeti' seçeneğini vurgulayan çözüm gezgini iletişim kutusunun ekran görüntüsü.

Hizmet Ara Sunucusu Sınıfının Bir Örneğini Oluşturma

Yönteminizin Main içinde aşağıdaki gibi proxy sınıfının yeni bir örneğini oluşturun:

using System;
using System.Data.Services.Client;
using System.Linq;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri uri = new Uri("http://localhost:1234/odata/");
            var container = new ProductService.Container(uri);

            // ...
        }
    }
}

Yeniden, hizmetinizin çalıştığı gerçek bağlantı noktası numarasını kullanın. Hizmetinizi dağıtırken canlı hizmetin URI'sini kullanacaksınız. Proxy'yi güncelleştirmeniz gerekmez.

Aşağıdaki kod, konsol penceresine istek URI'lerini yazdıran bir olay işleyicisi ekler. Bu adım gerekli değildir, ancak her sorgunun URI'lerini görmek ilginçtir.

container.SendingRequest2 += (s, e) =>
{
    Console.WriteLine("{0} {1}", e.RequestMessage.Method, e.RequestMessage.Url);
};

Hizmeti Sorgulama

Aşağıdaki kod, OData hizmetinden ürünlerin listesini alır.

class Program
{
    static void DisplayProduct(ProductService.Product product)
    {
        Console.WriteLine("{0} {1} {2}", product.Name, product.Price, product.Category);
    }

    // Get an entire entity set.
    static void ListAllProducts(ProductService.Container container)
    {
        foreach (var p in container.Products)
        {
            DisplayProduct(p);
        } 
    }
  
    static void Main(string[] args)
    {
        Uri uri = new Uri("http://localhost:18285/odata/");
        var container = new ProductService.Container(uri);
        container.SendingRequest2 += (s, e) =>
        {
            Console.WriteLine("{0} {1}", e.RequestMessage.Method, e.RequestMessage.Url);
        };

        // Get the list of products
        ListAllProducts(container);
    }
}

HTTP isteğini göndermek veya yanıtı ayrıştırmak için herhangi bir kod yazmanıza gerek olmadığını fark edin. Foreach döngüsünde koleksiyonu numaralandırdığınızda Container.Products proxy sınıfı bunu otomatik olarak yapar.

Uygulamayı çalıştırdığınızda çıkış aşağıdaki gibi görünmelidir:

GET http://localhost:60868/odata/Products
Hat 15.00   Apparel
Scarf   12.00   Apparel
Socks   5.00    Apparel
Yo-yo   4.95    Toys
Puzzle  8.00    Toys

Kimliğine göre varlık almak için yan where tümcesi kullanın.

// Get a single entity.
static void ListProductById(ProductService.Container container, int id)
{
    var product = container.Products.Where(p => p.ID == id).SingleOrDefault();
    if (product != null)
    {
        DisplayProduct(product);
    }
}

Bu konunun geri kalanında yalnızca hizmeti çağırmak için gereken kodun tamamını Main göstermeyeceğim.

Sorgu Seçeneklerini Uygula

OData, verileri filtrelemek, sıralamak, sayfaya eklemek vb. için kullanılabilecek sorgu seçeneklerini tanımlar. Hizmet proxy'sinde, çeşitli LINQ ifadelerini kullanarak bu seçenekleri uygulayabilirsiniz.

Bu bölümde kısa örnekler göstereceğim. Daha fazla ayrıntı için MSDN'de LINQ Ile İlgili Önemli Noktalar (WCF Veri Hizmetleri) konusuna bakın.

Filtreleme ($filter)

Filtrelemek için bir where yan tümce kullanın. Aşağıdaki örnek, ürün kategorisine göre filtreler.

// Use the $filter option.
static void ListProductsInCategory(ProductService.Container container, string category)
{
    var products =
        from p in container.Products
        where p.Category == category
        select p;
    foreach (var p in products)
    {
        DisplayProduct(p);
    }
}

Bu kod aşağıdaki OData sorgusuna karşılık gelir.

GET http://localhost/odata/Products()?$filter=Category eq 'apparel'

Proxy'nin yan tümcesini where bir OData $filter ifadesine dönüştürdüğüne dikkat edin.

Sıralama ($orderby)

Sıralamak için bir orderby yan tümce kullanın. Aşağıdaki örnek, en yüksekten en düşüğe kadar fiyata göre sıralanır.

// Use the $orderby option
static void ListProductsSorted(ProductService.Container container)
{
    // Sort by price, highest to lowest.
    var products =
        from p in container.Products
        orderby p.Price descending
        select p;

    foreach (var p in products)
    {
        DisplayProduct(p);
    }
}

İlgili OData isteği aşağıdadır.

GET http://localhost/odata/Products()?$orderby=Price desc

Client-Side Disk Belleği ($skip ve $top)

Büyük varlık kümeleri için istemci sonuç sayısını sınırlamak isteyebilir. Örneğin, bir istemci aynı anda 10 giriş gösterebilir. Buna istemci tarafı disk belleği adı verilir. (Sunucunun sonuç sayısını sınırladığı sunucu tarafı sayfalama da vardır.) İstemci tarafı disk belleği gerçekleştirmek için LINQ Skip ve Take yöntemlerini kullanın. Aşağıdaki örnek, ilk 40 sonucu atlar ve sonraki 10 sonucu alır.

// Use $skip and $top options.
static void ListProductsPaged(ProductService.Container container)
{
    var products =
        (from p in container.Products
          orderby p.Price descending
          select p).Skip(40).Take(10);

    foreach (var p in products)
    {
        DisplayProduct(p);
    }
}

İlgili OData isteği aşağıdadır:

GET http://localhost/odata/Products()?$orderby=Price desc&$skip=40&$top=10

Seçin ($select) ve Genişlet ($expand)

İlgili varlıkları eklemek için yöntemini kullanın DataServiceQuery<t>.Expand . Örneğin, her Productiçin öğesini Supplier eklemek için:

// Use the $expand option.
static void ListProductsAndSupplier(ProductService.Container container)
{
    var products = container.Products.Expand(p => p.Supplier);
    foreach (var p in products)
    {
        Console.WriteLine("{0}\t{1}\t{2}", p.Name, p.Price, p.Supplier.Name);
    }
}

İlgili OData isteği aşağıdadır:

GET http://localhost/odata/Products()?$expand=Supplier

Yanıtın şeklini değiştirmek için LINQ select yan tümcesini kullanın. Aşağıdaki örnek, diğer özellikler olmadan yalnızca her ürünün adını alır.

// Use the $select option.
static void ListProductNames(ProductService.Container container)
{

    var products = from p in container.Products select new { Name = p.Name };
    foreach (var p in products)
    {
        Console.WriteLine(p.Name);
    }
}

İlgili OData isteği aşağıdadır:

GET http://localhost/odata/Products()?$select=Name

Select yan tümcesi ilgili varlıkları içerebilir. Bu durumda Genişlet'i çağırmayın; ara sunucu, bu durumda genişletmeyi otomatik olarak içerir. Aşağıdaki örnek, her ürünün adını ve sağlayıcısını alır.

// Use $expand and $select options
static void ListProductNameSupplier(ProductService.Container container)
{
    var products =
        from p in container.Products
        select new
        {
            Name = p.Name,
            Supplier = p.Supplier.Name
        };
    foreach (var p in products)
    {
        Console.WriteLine("{0}\t{1}", p.Name, p.Supplier);
    }
}

İlgili OData isteği aşağıdadır. $expand seçeneğini içerdiğine dikkat edin.

GET http://localhost/odata/Products()?$expand=Supplier&$select=Name,Supplier/Name

$select ve $expand hakkında daha fazla bilgi için bkz. Web API 2'de $select, $expand ve $value kullanma.

Yeni Varlık Ekle

Varlık kümesine yeni bir varlık eklemek için öğesini çağırın AddToEntitySet. Burada EntitySet , varlık kümesinin adıdır. Örneğin, AddToProducts varlık kümesine Products yeni Product bir ekler. Ara sunucuyu oluşturduğunuzda, WCF Veri Hizmetleri bu kesin türdeki AddTo yöntemlerini otomatik olarak oluşturur.

// Add an entity.
static void AddProduct(ProductService.Container container, ProductService.Product product)
{
    container.AddToProducts(product);
    var serviceResponse = container.SaveChanges();
    foreach (var operationResponse in serviceResponse)
    {
        Console.WriteLine(operationResponse.StatusCode);
    }
}

İki varlık arasına bağlantı eklemek için AddLink ve SetLink yöntemlerini kullanın. Aşağıdaki kod yeni bir sağlayıcı ve yeni bir ürün ekler ve bunlar arasında bağlantılar oluşturur.

// Add entities with links.
static void AddProductWithSupplier(ProductService.Container container, 
    ProductService.Product product, ProductService.Supplier supplier)
{
    container.AddToSuppliers(supplier);
    container.AddToProducts(product);
    container.AddLink(supplier, "Products", product);
    container.SetLink(product, "Supplier", supplier);
    var serviceResponse = container.SaveChanges();
    foreach (var operationResponse in serviceResponse)
    {
        Console.WriteLine(operationResponse.StatusCode);
    }
}

Gezinti özelliği bir koleksiyon olduğunda AddLink kullanın. Bu örnekte, tedarikçideki Products koleksiyona bir ürün ekliyoruz.

Gezinti özelliği tek bir varlık olduğunda SetLink kullanın. Bu örnekte, üründe Supplier özelliğini ayarlıyoruz.

Güncelleştirme / Düzeltme Eki

Bir varlığı güncelleştirmek için UpdateObject yöntemini çağırın.

static void UpdatePrice(ProductService.Container container, int id, decimal price)
{
    var product = container.Products.Where(p => p.ID == id).SingleOrDefault();
    if (product != null)
    { 
        product.Price = price;
        container.UpdateObject(product);
        container.SaveChanges(SaveChangesOptions.PatchOnUpdate);
    }
}

Güncelleştirme , SaveChanges çağrısı yaptığınızda gerçekleştirilir. Varsayılan olarak, WCF bir HTTP MERGE isteği gönderir. PatchOnUpdate seçeneği WCF'ye bunun yerine HTTP PATCH göndermesini söyler.

Not

PATCH ve MERGE neden karşı karşıya? Özgün HTTP 1.1 belirtimi (RCF 2616), "kısmi güncelleştirme" semantiği ile hiçbir HTTP yöntemi tanımlamadı. Kısmi güncelleştirmeleri desteklemek için OData belirtimi MERGE yöntemini tanımlamıştı. 2010'da RFC 5789 , kısmi güncelleştirmeler için PATCH yöntemini tanımlamıştı. Bu blog gönderisindeki geçmişin bazılarını WCF Veri Hizmetleri Blog'da okuyabilirsiniz. Bugün, MERGE yerine PATCH tercih edilir. Web API iskelesi tarafından oluşturulan OData denetleyicisi her iki yöntemi de destekler.

Varlığın tamamını değiştirmek istiyorsanız (PUT semantiği), ReplaceOnUpdate seçeneğini belirtin. Bu, WCF'nin http PUT isteği göndermesine neden olur.

container.SaveChanges(SaveChangesOptions.ReplaceOnUpdate);

Varlığı Silme

Bir varlığı silmek için DeleteObject çağrısında bulunabilirsiniz.

static void DeleteProduct(ProductService.Container container, int id)
{
    var product = container.Products.Where(p => p.ID == id).SingleOrDefault();
    if (product != null)
    {
        container.DeleteObject(product);
        container.SaveChanges();
    }
}

OData Eylemi Çağırma

OData'da eylemler , varlıklarda CRUD işlemleri olarak kolayca tanımlanmayan sunucu tarafı davranışları eklemenin bir yoludur.

OData meta veri belgesinde eylemler açıklansa da, ara sunucu sınıfı bunlar için kesin olarak türlenmiş yöntemler oluşturmaz. Yine de genel Execute yöntemini kullanarak bir OData eylemi çağırabilirsiniz. Ancak, parametrelerin veri türlerini ve dönüş değerini bilmeniz gerekir.

Örneğin, RateProduct eylem türündeki Int32 "Derecelendirme" adlı parametreyi alır ve bir doubledöndürür. Aşağıdaki kodda bu eylemin nasıl çağrıldığı gösterilmektedir.

int rating = 2;
Uri actionUri = new Uri(uri, "Products(5)/RateProduct");
var averageRating = container.Execute<double>(
    actionUri, "POST", true, new BodyOperationParameter("Rating", rating)).First();

Daha fazla bilgi için bkz. Hizmet İşlemlerini ve Eylemlerini Çağırma.

Bir seçenek , Eylemi çağıran kesin olarak belirlenmiş bir yöntem sağlamak için Container sınıfını genişletmektir:

namespace ProductServiceClient.ProductService
{
    public partial class Container
    {
        public double RateProduct(int productID, int rating)
        {
            Uri actionUri = new Uri(this.BaseUri,
                String.Format("Products({0})/RateProduct", productID)
                );

            return this.Execute<double>(actionUri, 
                "POST", true, new BodyOperationParameter("Rating", rating)).First();
        }
    }
}