ASP.NET Çekirdeği ile RESTful API'ler oluşturma konusunda harika bir rehber

Temiz, sürdürülebilir RESTful API'lerin nasıl uygulanacağına dair adım adım kılavuz

Fotoğraf Jefferson Santos, Unsplash yayınlanan

genel bakış

RESTful yeni bir terim değildir. Web servislerinin müşteri uygulamalarından ve uygulamalarından veri aldığı ve gönderdiği mimari tarzı ifade eder. Bu uygulamaların amacı, farklı istemci uygulamalarının kullanacağı verileri merkezileştirmektir.

RESTful hizmetleri yazmak için doğru araçları seçmek çok önemlidir, çünkü ölçeklenebilirlik, bakım, dokümantasyon ve diğer tüm ilgili konularla ilgilenmemiz gerekir. ASP.NET Çekirdeği, bize bu hedeflere ulaşmak için harika, kullanımı kolay güçlü bir API verir.

Bu makalede, size ASP.NET Core çerçevesini kullanarak “neredeyse” gerçek bir dünya senaryosu için iyi yapılandırılmış bir RESTful API yazmayı göstereceğim. Geliştirme sürecini basitleştirmek için ortak kalıp ve stratejileri detaylandıracağım.

Ayrıca, gerekli işlevleri sağlamak için Entity Framework Core ve AutoMapper gibi ortak çerçeveleri ve kütüphaneleri nasıl entegre edeceğinizi göstereceğim.

Ön şartlar

Nesneye yönelik programlama kavramları hakkında bilgi sahibi olmanızı bekliyorum.

C # programlama dilinin birçok detayını kapsayacağım halde, bu konu hakkında temel bilgilere sahip olmanızı öneririm.

Ayrıca REST'in ne olduğunu, HTTP protokolünün nasıl çalıştığını, API uç noktalarının ve JSON'un ne olduğunu bildiğinizi varsayıyorum. İşte bu konuda harika bir tanıtım dersi. Nihai gereksinim, ilişkisel veritabanlarının nasıl çalıştığını anlamanızdır.

Benimle birlikte kod yazmak için, API'yi test etmek için kullanacağım aracı olan .NET Core 2.2'yi ve ayrıca Postacı'yı yüklemeniz gerekecektir. API geliştirmek için Visual Studio Code gibi bir kod editörü kullanmanızı öneririm. Tercih ettiğiniz kod editörünü seçin. Bu kod düzenleyiciyi seçerseniz, daha iyi kod vurgulaması için C # uzantısını yüklemenizi öneririm.

Son sonucu kontrol etmek için bu makalenin sonunda API’nin Github deposuna bir link bulabilirsiniz.

Kapsam

Bir süpermarket için kurgusal bir web API yazalım. Aşağıdaki kapsamı uygulamamız gerektiğini düşünelim:

  • Müşteri uygulamalarının süpermarketin ürün kataloğunu yönetmesini sağlayan bir RESTful hizmeti oluşturun. Süt ürünleri ve kozmetik ürünleri gibi ürün kategorileri oluşturmak, okumak, düzenlemek ve silmek ve ayrıca bu kategorilerin ürünlerini yönetmek için uç noktaları göstermesi gerekir.
  • Kategoriler için isimlerini kaydetmemiz gerekiyor. Ürünler için, adlarını, ölçüm birimini (örneğin, ağırlıkça ölçülen ürünler için KG), paket içindeki miktarları (örneğin, ürün bir paket bisküvi ise 10) ve ilgili kategorileri saklamamız gerekir.

Örneği basitleştirmek için, stoktaki ürünleri, ürün nakliyesini, güvenliği ve diğer işlevleri kullanmayacağım. ASP.NET Core'un nasıl çalıştığını göstermek için verilen kapsam yeterlidir.

Bu hizmeti geliştirmek için temel olarak iki API uç noktasına ihtiyacımız var: biri kategorileri yönetmek, diğeri ürünleri yönetmek için. JSON iletişimi açısından, cevapları aşağıdaki şekilde düşünebiliriz:

API bitiş noktası: / api / category

JSON Yanıtı (GET istekleri için):

{
  [
    {"id": 1, "isim": "Meyve ve Sebzeler"},
    {"id": 2, "name": "Ekmekler"},
    … // Diğer kategoriler
  ]
}

API bitiş noktası: / api / ürünler

JSON Yanıtı (GET istekleri için):

{
  [
    {
      "kimliği": 1,
      "isim": "Şeker",
      "miktarInPackage": 1,
      "unitOfMurement": "KG"
      "kategori": {
        "kimliği": 3,
        "isim": "Şeker"
      }
    },
    … // Diğer ürünler
  ]
}

Uygulamayı yazmaya başlayalım.

Adım 1 - API'yi oluşturma

Öncelikle, web hizmeti için klasörler yapısını oluşturmalı ve daha sonra temel bir web API'sini taramak için .NET CLI araçlarını kullanmalıyız. Terminal veya komut istemini açın (kullandığınız işletim sistemine göre değişir) ve aşağıdaki komutları sırasıyla yazın:

mkdir src / Süpermarket.API
cd src / Süpermarket.API
dotnet yeni webapi

İlk iki komut yalnızca API için yeni bir dizin oluşturur ve geçerli konumu yeni klasöre değiştirir. Sonuncusu, Web API şablonunu takip eden, geliştirmekte olduğumuz uygulama türü olan yeni bir proje oluşturur. Bu komut ve bu bağlantıyı kontrol ederek oluşturabileceğiniz diğer proje şablonları hakkında daha fazla bilgi edinebilirsiniz.

Yeni dizin şimdi aşağıdaki yapıya sahip olacaktır:

Proje Yapısı

Yapıya Genel Bakış

Bir ASP.NET Core uygulaması, Başlangıç ​​sınıfında yapılandırılmış bir grup orta katmandan (uygulama boru hattına eklenmiş uygulamanın küçük parçaları), istekleri ve yanıtları işleyen) oluşur. Daha önce Express.js gibi çerçevelerle daha önce çalıştıysanız, bu konsept sizin için yeni değil.

Uygulama başladığında, Program sınıfından Ana yöntem çağrılır. Başlangıç ​​yapılandırmasını kullanarak, uygulamayı belirli bir bağlantı noktası üzerinden HTTP yoluyla gösteren (varsayılan olarak, HTTP için 5000 ve HTTPS için 5001) varsayılan bir web sunucusu oluşturur.

Controllers klasörü içindeki ValuesController sınıfına bakın. API, rota / api / değerler üzerinden istek aldığında çağrılacak yöntemleri ortaya koyar.

Bu kodun bir bölümünü anlamadıysanız endişelenmeyin. Gerekli API uç noktalarını geliştirirken her birini ayrıntılı olarak açıklayacağım. Şimdilik, kullanmayacağımızdan bu sınıfı silin.

Adım 2 - Etki Alanı Modellerini Oluşturma

Uygulamayı basit ve bakımı kolay tutacak bazı tasarım kavramları uygulayacağım.

Kendiniz tarafından anlaşılabilecek ve korunabilecek bir kod yazmak bu kadar zor değil, ancak bir ekibin parçası olarak çalışacağınızı aklınızda bulundurmanız gerekir. Kodunuzu nasıl yazdığınıza dikkat etmezseniz, sonuç size ve takım arkadaşlarınıza sürekli baş ağrıları verecek bir canavar olacaktır. Aşırı geliyor, değil mi? Ama inan bana, gerçek bu.

wtf - smitty42 tarafından kod kalitesi ölçümü CC-BY-ND 2.0 altında lisanslanmıştır

Etki alanı katmanını yazarak başlayalım. Bu katman, model sınıflarımıza, ürünlerimizi ve kategorilerimizi temsil edecek sınıflara, ayrıca depo ve hizmet arayüzlerine sahip olacaktır. Bu son iki kavramı bir süre sonra açıklayacağım.

Supermarket.API dizininin içinde Domain adlı yeni bir klasör oluşturun. Yeni etki alanı klasöründe, Models adında başka bir tane oluşturun. Bu klasöre eklemek zorunda olduğumuz ilk model Kategori. Başlangıçta, basit bir Düz Eski CLR Nesne (POCO) sınıfı olacaktır. Bu, sınıfın yalnızca temel bilgilerini tanımlayan özelliklere sahip olacağı anlamına gelir.

Sınıf, kategoriyi tanımlamak için bir Id özelliğine ve bir Nameproperty'ye sahiptir. Ayrıca bir Ürünümüz de var. Bu sonuncusu Entity Framework Core, ORM'nin çoğu ASP.NET Core uygulamasının, veri tabanına veri tutmak, kategoriler ve ürünler arasındaki ilişkiyi haritalandırmak için kullandığı ORM tarafından kullanılacaktır. Ayrıca, bir kategoride ilgili birçok ürün olduğundan, nesne yönelimli programlama açısından da mantıklı düşünmeyi sağlar.

Ayrıca ürün modelini oluşturmalıyız. Aynı klasöre yeni bir Ürün sınıfı ekleyin.

Ürünün ayrıca Kimlik ve ad için özellikleri de vardır. Bu aynı zamanda, bir pakette kaç tane ürün bulunduğumuzu (uygulama kapsamındaki bisküvi örneğini hatırlayın) ve bir UnitOfMeasurement özelliği olduğunu söyleyen bir özellik olan QuantityInPackage özelliğidir. Bu, olası ölçü birimlerinin bir numaralandırmasını temsil eden bir numara türüyle temsil edilir. Son iki özellik, CategoryId ve Category, ürünler ile kategoriler arasındaki ilişkiyi haritalamak için ORM tarafından kullanılacaktır. Bir ürünün bir ve yalnızca bir kategorisi olduğunu gösterir.

Etki alanı modellerimizin son bölümünü EUnitOfMeasurement enum'u tanımlayalım.

Kurallara göre, enums'lerin adlarının önünde bir “E” ile başlaması gerekmez, ancak bazı kütüphanelerde ve çerçevelerde bu öneki, enumları arabirimlerden ve sınıflardan ayırmanın bir yolu olarak bulacaksınız.

Kod gerçekten basittir. Burada, sadece ölçüm birimleri için bir avuç olasılık tanımladık, ancak, gerçek bir süpermarket sisteminde, başka birçok ölçüm birimlerine ve belki bunun için ayrı bir modele sahip olabilirsiniz.

Her numaralandırma olasılığına uygulanan Açıklama özniteliğine dikkat edin. Bir nitelik, sınıflar, arayüzler, özellikler ve C # dilinin diğer bileşenleri üzerindeki meta verileri tanımlamanın bir yoludur. Bu durumda, ürünleri API uç noktalarının yanıtlarını basitleştirmek için kullanacağız, ancak şimdilik bununla ilgilenmenize gerek yok. Daha sonra buraya geri geleceğiz.

Temel modellerimiz kullanıma hazır. Şimdi tüm kategorileri yönetecek olan API uç noktasını yazmaya başlayabiliriz.

Adım 3 - Kategoriler API'si

Denetleyiciler klasöründe, CategoriesController adlı yeni bir sınıf ekleyin.

Kurallara göre, bu klasördeki “Controller” ekiyle biten tüm sınıflar uygulamamızın denetleyicileri olacaktır. İstekleri ve cevapları yerine getirecekleri anlamına geliyor. Bu sınıfı, Microsoft.AspNetCore.Mvc ad alanında tanımlanan Controller sınıfından miras almanız gerekir.

Bir ad alanı, ilgili sınıflar, arayüzler, numaralamalar ve yapılar grubundan oluşur. Javascript dilinin modüllerine veya Java paketlerine benzer bir şey olarak düşünebilirsiniz.

Yeni kontrol cihazı rota / api / kategoriler yoluyla cevap vermelidir. Bunu, sınıf adının üzerine Route özniteliğini ekleyerek, yolun konvansiyonel olarak sınıf adını denetleyici soneki olmadan kullanması gerektiğini belirten bir yer tutucu belirleyerek elde ederiz.

GET isteklerini yerine getirmeye başlayalım. Her şeyden önce, birisi GET fiili aracılığıyla / api / kategorilerinden veri talep ettiğinde, API'nin tüm kategorileri döndürmesi gerekir. Bu amaçla bir kategori servisi yaratabiliriz.

Kavramsal olarak, bir hizmet temelde bazı iş mantığını ele alma yöntemlerini tanımlayan bir sınıf veya arayüzdür. Kimlik doğrulama ve yetkilendirme, ödemeler, karmaşık veri akışları, önbelleğe alma ve diğer hizmetler veya modeller arasında biraz etkileşim gerektiren görevler gibi iş mantığını idare edecek hizmetler oluşturmak, birçok farklı programlama dilinde yaygın bir uygulamadır.

Hizmetleri kullanarak, istekleri ve yanıt işlemlerini görevleri tamamlamak için gereken gerçek mantıktan uzaklaştırabiliriz.

Başlangıçta oluşturacağımız hizmet, tek bir davranış veya yöntemi tanımlayacaktır: bir liste yöntemi. Bu yöntemin veritabanındaki tüm kategorileri döndürmesini bekliyoruz.

Basit olması için, bu durumda veri sayfalandırma veya filtreleme ile ilgilenmeyeceğiz. Gelecekte bu özelliklerin nasıl kolayca kullanılabileceğini gösteren bir makale yazacağım.

C # 'daki (ve örneğin Java gibi diğer nesneye yönelik dillerde) beklenen bir davranışı tanımlamak için bir arayüz tanımlarız. Bir arayüz bir şeyin nasıl çalışması gerektiğini anlatır, ancak davranış için gerçek mantığı uygulamaz. Mantık, arayüzü uygulayan sınıflarda uygulanır. Bu kavram sizin için net değilse, endişelenmeyin. Bir süre sonra anlayacaksın.

Etki alanı klasöründe, Services adlı yeni bir dizin oluşturun. Orada, ICategoryService adlı bir arayüz ekleyin. Kurallara göre, tüm arayüzler C # harfinde “I” harfiyle başlamalıdır. Arayüz kodunu aşağıdaki gibi tanımlayın:

ListAsync yönteminin uygulamaları eşzamanlı olarak kategorilerin bir numaralandırmasını döndürmelidir.

Döndürmeyi kapsayan Task sınıfı, zaman uyumsuzluğunu gösterir. Veriyi döndürmek için veritabanının bir işlemi tamamlamasını beklememiz gerektiğinden, asenkronize bir yöntem düşünmemiz gerekir ve bu işlem biraz zaman alabilir. Ayrıca “async” sonekine dikkat edin. Bu, yöntemimizin eşzamansız olarak yürütülmesi gerektiğini belirten bir kongredir.

Çok fazla sözleşmemiz var, değil mi? Kişisel olarak hoşuma gidiyor, çünkü .NET teknolojisini kullanan bir şirkette yeniyseniz bile uygulamaların okunmasını kolaylaştırıyor.

“- Tamam, bu arayüzü tanımladık ama hiçbir şey yapmıyor. Nasıl faydalı olabilir? ”

Javascript veya başka bir güçlü olmayan dilden oluşan bir dilden geliyorsanız, bu kavram garip görünebilir.

Arayüzler, istenen davranışı gerçek uygulamadan soyutlamamıza izin verir. Bağımlılık enjeksiyonu olarak bilinen bir mekanizma kullanarak, bu arayüzleri uygulayabilir ve diğer bileşenlerden izole edebiliriz.

Temel olarak, bağımlılık enjeksiyonunu kullandığınızda, bir arayüz kullanarak bazı davranışları tanımlarsınız. Ardından, arabirimi uygulayan bir sınıf oluşturursunuz. Son olarak, arayüzden referansları yarattığınız sınıfa bağlarsınız.

“- Gerçekten kafa karıştırıcı geliyor. Bunları bizim için yapan bir sınıf oluşturamaz mıyız? ”

API'mızı uygulamaya devam edelim ve bu yaklaşımı neden kullandığınızı anlayacaksınız.

CategoriesKontrolör kodunu aşağıdaki gibi değiştirin:

Kontrolcümüz için bir yapıcı işlevi tanımladım (sınıfın yeni bir örneğini oluştururken bir yapıcı çağrılır) ve bir ICategoryService örneği alır. Bunun anlamı servis arayüzünü uygulayan herhangi bir şey olabilir. Bu örneği özel, salt okunur bir alanda _categoryService'de saklıyorum. Bu alanı, kategori hizmet uygulamamızın yöntemlerine erişmek için kullanacağız.

Bu arada, alt çizgi öneki, bir alanı belirtmek için başka bir genel kuraldır. Özel olarak, bu sözleşme, .NET’in resmi adlandırma kuralları kılavuzunda önerilmemektedir, ancak sınıf alanlarını yerel değişkenlerden ayırmak için “this” anahtar sözcüğünü kullanmaktan kaçınmanın bir yolu olarak yaygın bir uygulamadır. Şahsen okumanın daha temiz olduğunu düşünüyorum ve pek çok çerçeve ve kütüphane bu sözleşmeyi kullanıyor.

Yapıcının altında, / api / category isteklerini yerine getirecek yöntemi tanımladım. HttpGet özelliği, ASP.NET Core boru hattına GET isteklerini yerine getirmek için kullanmasını söyler (bu özellik atlanabilir, ancak daha kolay okunabilirlik için yazmak daha iyidir).

Yöntem, tüm kategorileri listelemek için kategori hizmet örneğimizi kullanır ve ardından kategorileri müşteriye geri gönderir. Çerçeve boru hattı, verilerin bir JSON nesnesine seri hale getirilmesini işler. IEnumerable türü, çerçeveye kategori numaralandırması döndürmek istediğimizi, async anahtar sözcüğünden önce gelen Görev türü, boru hattına bu yöntemin eşzamansız olarak yürütülmesi gerektiğini söyler. Son olarak, bir eşzamansız yöntem tanımladığımızda, bir süre alabilecek görevler için await anahtar sözcüğünü kullanmalıyız.

Tamam, API’nizin ilk yapısını tanımladık. Şimdi, kategori hizmetini gerçekten uygulamak gerekiyor.

Adım 4 - Kategoriler Hizmetini Uygulama

API'nin kök klasöründe (Supermarket.API klasörü), Hizmetler adında yeni bir tane oluşturun. Burada tüm servis uygulamalarını koyacağız. Yeni klasörün içine CategoryService adlı yeni bir sınıf ekleyin. Kodu aşağıdaki gibi değiştirin:

Bu, sadece arayüz uygulaması için temel koddur, ancak yine de herhangi bir mantığı ele almıyoruz. Giriş yönteminin nasıl çalışması gerektiğini düşünelim.

Veritabanına erişmemiz ve tüm kategorileri döndürmemiz gerekiyor, sonra bu verileri müşteriye iade etmemiz gerekiyor.

Hizmet sınıfı, veri erişimini işlemesi gereken bir sınıf değildir. Veritabanlarından verileri yönetmek için kullanılan Depo Modeli adı verilen bir kalıp vardır.

Havuz Şablonunu kullanırken, temel olarak veri erişimini işlemek için tüm mantığı içine alan depo sınıflarını tanımlarız. Bu depolar, belirli bir modeldeki nesneleri toplama, düzenleme, düzenleme gibi işlemleri listeleme, oluşturma, düzenleme ve silme yöntemlerini ortaya koymaktadır. Dahili olarak, bu yöntemler, veritabanının erişimini uygulamanın geri kalanından izole ederek CRUD işlemlerini gerçekleştirmek için veritabanıyla konuşur.

Hizmetimizin, nesnelerin listesini almak için bir kategori deposuyla konuşması gerekir.

Kavramsal olarak, bir servis işlemleri gerçekleştirmek için bir veya daha fazla havuz veya diğer servislerle “konuşabilir”.

Veri erişim mantığını işlemek için yeni bir tanım oluşturmak gereksiz olabilir, ancak bir süre sonra bu mantığı hizmet sınıfından ayırmanın gerçekten avantajlı olduğunu göreceksiniz.

Veri tabanı iletişimini kategorilere devam etmenin bir yolu olarak kullanmaktan sorumlu olacak bir depo oluşturalım.

Adım 5 - Kategoriler Havuzu ve Kalıcılık Katmanı

Etki alanı klasörünün içinde, havuzları adlı yeni bir dizin oluşturun. Ardından, ICategoryRespository adlı yeni bir arayüz ekleyin. Arabirimi aşağıdaki gibi tanımlayın:

İlk kod temel olarak servis arayüzünün koduyla aynıdır.

Arabirimi tanımladıktan sonra, verileri geri döndürmek için bir ICategoryRepository örneği kullanarak hizmet sınıfına dönebilir ve listeleme yöntemini uygulamayı bitirebiliriz.

Şimdi kategori havuzunun gerçek mantığını uygulamak zorundayız. Bunu yapmadan önce veritabanına nasıl erişeceğimizi düşünmeliyiz.

Bu arada, hala bir veritabanımız yok!

Entity Framework Çekirdeğini (basitlik için EF Çekirdeği olarak adlandırırım) veritabanı ORM olarak kullanacağız. Bu çerçeve, varsayılan ORM olarak ASP.NET Core ile birlikte gelir ve uygulamalarımızın sınıflarını veritabanı tablolarıyla eşleştirmemizi sağlayan dost bir API sunar.

EF Çekirdeği ayrıca önce uygulamamızı tasarlamamıza ve ardından kodumuzda tanımladığımıza göre bir veritabanı oluşturmamıza olanak tanır. Bu tekniğe önce kod denir. Bir veritabanı oluşturmak için ilk önce kod yaklaşımını kullanacağız (bu örnekte, aslında bir bellek içi veritabanı kullanacağım, ancak bunu kolayca bir SQL Server veya MySQL sunucu örneğiyle değiştirebileceksiniz, Örneğin).

API'nin kök klasöründe Kalıcılık adlı yeni bir dizin oluşturun. Bu dizin, depo uygulamaları gibi veritabanına erişmek için gereken her şeye sahip olacak.

Yeni klasörün içinde, Bağlamlar adlı yeni bir dizin oluşturun ve sonra AppDbContext adlı yeni bir sınıf ekleyin. Bu sınıfın, modellerinizi veritabanı tablolarıyla eşlemek için kullandığı bir EF Core sınıfı olan DbContext'i devralması gerekir. Kodu aşağıdaki şekilde değiştirin:

Bu sınıfa eklediğimiz yapıcı, bağımlılık enjeksiyonuyla veritabanı konfigürasyonunu temel sınıfa geçirmekten sorumludur. Bunun nasıl çalıştığını bir dakika içinde göreceksiniz.

Şimdi iki tane DbSet özelliği yaratmamız gerekiyor. Bu özellikler, modelleri veritabanı tablolarıyla eşleyen kümelerdir (benzersiz nesnelerin koleksiyonları).

Ayrıca, modellerin özelliklerini hangi tabloların sütunlarıyla eşleştirmeliyiz, hangi özelliklerin yabancı anahtarlar, sütun tipleri vb. Olan birincil anahtarlar olduğunu belirtmeliyiz. veritabanı eşlemesini belirtin. AppDbContext sınıfını aşağıdaki gibi değiştirin:

Kod sezgiseldir.

Modellerimizin hangi tablolarla eşleştirilmesi gerektiğini belirtiyoruz. Ayrıca, birincil anahtarları, HasKey yöntemini, tablo sütunlarını, Property yöntemini kullanarak ve IsRequired, HasMaxLength ve ValueGeneratedOnAdd gibi bazı kısıtlamaları, “akıcı bir şekilde” lambda ifadeleriyle (zincirleme yöntemleri) kullanarak belirleriz.

Aşağıdaki kod parçasına bir göz atın:

builder.Entity  ()
       .HasMany (p => p.Ürünler)
       .WithOne (p => p.Category)
       .HasForeignKey (p => p.CategoryId);

Burada tablolar arasında bir ilişki belirtiyoruz. Bir kategorinin pek çok ürünü olduğunu söylüyoruz ve bu ilişkiyi haritalandıracak özellikleri belirliyoruz (Ürünler, Kategori sınıfından ve Kategori, Ürün sınıfından). Ayrıca yabancı anahtarı da (CategoryId) ayarladık.

EF Core'u kullanarak bire bir ve çoktan çoğa ilişkilerin nasıl yapılandırılacağını ve bir bütün olarak nasıl kullanılacağını öğrenmek istiyorsanız bu eğitime bakın.

HasData yöntemi ile veri tohumlama için bir yapılandırma da vardır:

builder.Entity  (). HasData
(
  yeni kategori {Id = 100, Name = "Meyve ve Sebzeler"},
  yeni Kategori {Id = 101, Ad = "Süt"}
);

Burada varsayılan olarak iki örnek kategori ekliyoruz. API uç noktamızı bitirdikten sonra test etmek için bu gereklidir.

Uyarı: Hafıza içi sağlayıcı çalışmasını gerektirdiği için Id özelliklerini burada manuel olarak ayarlıyoruz. Otomatik olarak oluşturulan tanımlayıcılar ve tohum verileri arasında çarpışmayı önlemek için tanımlayıcıları büyük numaralara ayarlıyorum.
Bu sınırlama, gerçek ilişkisel veritabanı sağlayıcılarında mevcut değildir; bu nedenle, örneğin SQL Server gibi bir veritabanı kullanmak istiyorsanız, bu tanımlayıcıları belirtmeniz gerekmez. Bu davranışı anlamak istiyorsanız, bu Github konusunu kontrol edin.

Veritabanı bağlamı sınıfını uyguladıktan sonra, kategori havuzunu uygulayabiliriz. Kalıcılık klasörü içindeki havuzları adlı yeni bir klasör ekleyin ve sonra BaseRepository adlı yeni bir sınıf ekleyin.

Bu sınıf, tüm depolarımızın miras alacağı soyut bir sınıftır. Soyut bir sınıf doğrudan örnekleri olmayan bir sınıftır. Örnekleri oluşturmak için doğrudan sınıflar oluşturmanız gerekir.

BaseRepository, bağımlılık enjeksiyonuyla AppDbContext örneğimizi alıyor ve veritabanı işlemlerini yürütmek için ihtiyaç duyduğumuz tüm yöntemlere erişim sağlayan _context adlı korumalı bir özelliği (yalnızca çocuk sınıfları tarafından erişilebilir olan bir özellik) ortaya koyuyor.

CategoryRepository adlı aynı klasöre yeni bir sınıf ekleyin. Şimdi depo mantığını gerçekten uygulayacağız:

Havuz, BaseRepository'yi devralır ve ICategoryRepository'yi uygular.

Liste yöntemini uygulamanın ne kadar basit olduğuna dikkat edin. Kategoriler tablosuna erişmek için ayarlanmış Kategoriler veritabanını kullanıyoruz ve daha sonra bir sorgunun sonucunu bir kategori koleksiyonuna dönüştürmekten sorumlu olan ToListAsync uzantılı yöntemini çağırıyoruz.

EF Çekirdeği, yöntem çağrımızı bir SQL sorgusuna, en verimli şekilde çevirir. Sorgu yalnızca verilerinizi bir koleksiyona dönüştürecek bir yöntem çağırdığınızda veya belirli verileri almak için bir yöntem kullandığınızda uygulanır.

Artık kategoriler kontrolörü, servis ve veri havuzunu temiz bir şekilde uyguladık.

Sadece yapmaları gerekeni yapan sınıflar yaratarak endişelerimizi ayırdık.

Uygulamayı test etmeden önceki son adım, ASP.NET Core bağımlılık enjeksiyon mekanizmasını kullanarak arayüzlerimizi ilgili sınıflara bağlamaktır.

Adım 6 - Bağımlılık Enjeksiyonunu Yapılandırma

Nihayet bu kavramın nasıl çalıştığını anlamanızın zamanı geldi.

Uygulamanın kök klasöründe, Başlangıç ​​sınıfını açın. Bu sınıf, uygulama başladığında her türlü konfigürasyonun yapılandırılmasından sorumludur.

ConfigureServices ve Configure yöntemleri, uygulamanın nasıl çalışması gerektiğini ve hangi bileşenleri kullanması gerektiğini yapılandırmak için çalışma zamanında çerçeve boru hattı tarafından çağrılır.

ConfigureServices yöntemine bir göz atın. Burada, uygulamayı MVC boru hattını kullanacak şekilde yapılandıran tek bir satır var; bu, temel olarak uygulamanın denetleyici sınıflarını kullanarak istekleri ve yanıtları ele alacağı anlamına geliyor (burada sahnelerin arkasında daha fazla şeyler oluyor, ama bilmeniz gerekenler bu şimdilik).

Bağımlılık bağlayıcılarımızı yapılandırmak için hizmetler parametresine erişen ConfigureServices yöntemini kullanabiliriz. Tüm yorumları kaldırarak sınıf kodunu temizleyin ve kodu aşağıdaki gibi değiştirin:

Şu kod parçasına bakın:

services.AddDbContext  (options => {
  options.UseInMemoryDatabase ( "süpermarket-api-bellek");
});

Burada veritabanı içeriğini yapılandırıyoruz. ASP.NET Core'a, AppDbContext'imizi, metodumuza argüman olarak iletilen dizgenin tanımladığı bir bellek içi veritabanı uygulaması ile kullanmalarını söyleriz. Genellikle, bellek içi sağlayıcı, entegrasyon testleri yazarken kullanılır, ancak burada basitlik için kullanıyorum. Bu şekilde, uygulamayı test etmek için gerçek bir veritabanına bağlanmamız gerekmez.

Bu satırların yapılandırması, kapsamlı bir kullanım ömrü kullanan bağımlılık enjeksiyonuna yönelik veritabanı bağlamımızı dahili olarak yapılandırır.

Kapsamlı kullanım ömrü, ASP.NET Core boru hattına, bir yapıcı argümanı olarak AppDbContext örneğini alan bir sınıfı çözmesi gerektiğinde, sınıfın aynı örneğini kullanması gerektiğini söyler. Bellekte bir örnek yoksa, boru hattı yeni bir örnek oluşturacak ve belirli bir istek sırasında ihtiyaç duyan tüm sınıflarda yeniden kullanacaktır. Bu şekilde, kullanmanız gerektiğinde sınıf örneğini el ile oluşturmanız gerekmez.

Resmi belgeleri okumayı kontrol edebileceğiniz başka ömür boyu kapsamları da var.

Bağımlılık enjeksiyon tekniği bize aşağıdakiler gibi birçok avantaj sağlar:

  • Kod tekrar kullanılabilirliği;
  • Daha iyi üretkenlik, çünkü uygulamayı değiştirmek zorunda olduğumuzda, bu özelliği kullandığınız yüz yeri değiştirmek için uğraşmamız gerekmez;
  • Arabirimleri yapıcı argüman olarak iletmek zorunda olduğumuz sahte (sınıfların sahte uygulaması) kullanarak test etmek zorunda olduğumuzu izole edebileceğimizden uygulamayı kolayca test edebilirsiniz;
  • Bir sınıf kurucu aracılığıyla daha fazla bağımlılık alması gerektiğinde, örneklerin oluşturulduğu tüm yerleri manuel olarak değiştirmeniz gerekmez (bu harika!).

Veritabanı içeriğini yapılandırdıktan sonra, servisimizi ve havuzunu ilgili sınıflara da bağlarız.

services.AddScoped  ();
services.AddScoped  ();

Burada ayrıca kapsamlı bir kullanım ömrü kullanıyoruz, çünkü bu sınıfların dahili olarak veritabanı bağlamı sınıfını kullanması gerekiyor. Bu durumda aynı kapsamı belirtmek mantıklıdır.

Artık bağımlılık bağlayıcılarımızı yapılandırdığımızda, veritabanının başlangıçtaki verilerimizi doğru bir şekilde sıralayabilmesi için Program sınıfında küçük bir değişiklik yapmamız gerekiyor. Bu adım yalnızca bellek içi veritabanı sağlayıcısı kullanılırken gereklidir (nedenini anlamak için bu Github konusuna bakın).

Bellek içi bir sağlayıcı kullandığımızdan bu yana uygulama başladığında veritabanımızın “yaratılacağını” garanti altına almak için Ana yöntemi değiştirmek gerekliydi. Bu değişiklik olmadan, tohumlamak istediğimiz kategoriler yaratılmayacak.

Uygulanan tüm temel özelliklerle, API uç noktamızı test etme zamanı geldi.

Adım 7 - Kategoriler API'sini Test Etme

API kök klasöründe terminal veya komut istemini açın ve aşağıdaki komutu yazın:

dotnet run

Yukarıdaki komut uygulamayı başlatır. Konsol buna benzer bir çıktı gösterecek:

bilgileri: Microsoft.EntityFrameworkCore.Infrastructure [10403]
Varlık Çerçevesi Çekirdeği 2.2.0-rtm-35687, seçeneklerle "Microsoft.EntityFrameworkCore.InMemory" sağlayıcısı kullanarak "AppDbContext" uygulamasını başlattı: StoreName = süpermarket-api-bellekte
info: Microsoft.EntityFrameworkCore.Update [30100]
Bellek içi deposuna 2 varlık kaydedildi.
info: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager [0]
Kullanıcı profili mevcut. Anahtar deposu olarak ‘C: \ Users \ evgomes \ AppData \ Local \ ASP.NET \ DataProtection-Key’leri ve durmadan anahtarları şifrelemek için Windows DPAPI’yı kullanma.
Barındırma ortamı: Geliştirme
İçerik kök yolu: C: \ Users \ evgomes \ Desktop \ Öğreticiler \ src \ Supermarket.API
Şimdi dinliyor: https: // localhost: 5001
Şimdi dinleyeceğim: http: // localhost: 5000
Uygulama başladı. Kapatmak için Ctrl + C tuşlarına basın.

Veritabanını başlatmak için EF Çekirdeğinin çağrıldığını görebilirsiniz. Son satırlar uygulamanın hangi portlarda çalıştığını gösterir.

Bir tarayıcı açın ve http: // localhost: 5000 / api / category (veya konsol çıktısında görüntülenen URL’ye) gidin. HTTPS nedeniyle bir güvenlik hatası görürseniz, uygulama için bir istisna ekleyin.

Tarayıcı, aşağıdaki JSON verilerini çıktı olarak gösterecek:

[
  {
     "kimlik": 100,
     "name": "Meyve ve Sebzeler",
     "ürünler": []
  },
  {
     "kimlik": 101
     "name": "Süt",
     "ürünler": []
  }
]

Burada veritabanı bağlamını yapılandırırken veritabanına eklediğimiz verileri görüyoruz. Bu çıktı kodumuzun çalıştığını onaylar.

Çok az sayıda kod satırı içeren bir GET API uç noktası oluşturdunuz ve API mimarisi nedeniyle değiştirilmesi gerçekten kolay olan bir kod yapısına sahipsiniz.

Şimdi, iş gereksinimlerine göre ayarlamanız gerektiğinde bu kodu değiştirmenin ne kadar kolay olduğunu göstermenin zamanı geldi.

Adım 8 - Kategori Kaynak Oluşturma

API bitiş noktasının özelliklerini hatırlıyorsanız, gerçek JSON yanıtımızın bir ekstra özelliği olduğunu fark ettiniz: bir ürün dizisi. İstediğiniz yanıtın örneğine bir göz atın:

{
  [
    {"id": 1, "isim": "Meyve ve Sebzeler"},
    {"id": 2, "name": "Ekmekler"},
    … // Diğer kategoriler
  ]
}

Ürünler dizisi şu anki JSON cevabımızda mevcuttur, çünkü Kategori modelimiz, belirli bir kategorideki ürünleri haritalandırmak için EF Core tarafından ihtiyaç duyulan bir Ürün özelliğine sahiptir.

Bu mülkü cevabımızda istemiyoruz, ancak bu mülkü hariç tutacak şekilde model sınıfımızı değiştiremeyiz. Kategori verilerini yönetmeye çalıştığımızda EF Core'un hatalar atmasına neden olacaktı ve aynı zamanda etki alanı modeli tasarımımızı da bozacaktı çünkü ürün içermeyen bir ürün kategorisine sahip olmak mantıklı değil.

Yalnızca süpermarket kategorilerinin tanımlayıcılarını ve adlarını içeren JSON verilerini döndürmek için bir kaynak sınıfı oluşturmamız gerekir.

Kaynak sınıfı, bazı belirli bilgileri göstermek için yalnızca istemci uygulamaları ile API uç noktaları arasında, genellikle JSON verileri biçiminde değiştirilecek olan temel bilgileri içeren bir sınıftır.

API uç noktalarından gelen tüm yanıtlar bir kaynak döndürmelidir.

İstemci uygulamasının ihtiyaç duymadığı veya sahip olma yetkisi olmadığına dair bilgiler içerebileceğinden, gerçek model gösterimini yanıt olarak geri vermek kötü bir uygulamadır (örneğin, bir kullanıcı modeli kullanıcı şifresinin bilgisini döndürebilir) , hangi büyük bir güvenlik sorunu olurdu).

Ürünler olmadan sadece kategorilerimizi temsil etmek için bir kaynağa ihtiyacımız var.

Artık bir kaynağın ne olduğunu bildiğinize göre, onu uygulayalım. Her şeyden önce, çalışan uygulamayı komut satırında Ctrl + C tuşlarına basarak durdurun. Uygulamanın kök klasöründe, Kaynaklar adlı yeni bir klasör oluşturun. Orada CategoryResource adlı yeni bir sınıf ekleyin.

Kategori hizmetimiz tarafından sağlanan kategori model koleksiyonumuzu bir kategori kaynak koleksiyonuyla eşlemeliyiz.

Nesneler arasındaki eşlemeyi işlemek için Otomatik Harita adlı bir kütüphane kullanırız. AutoMapper, .NET dünyasında çok popüler bir kütüphanedir ve birçok ticari ve açık kaynaklı projede kullanılır.

AutoMapper'ı uygulamamıza eklemek için komut satırına aşağıdaki satırları yazın:

dotnet Paket ekle AutoMapper
dotnet AutoMapper.Extensions.Microsoft.DependencyInjection paketini ekleyin

AutoMapper'ı kullanmak için iki şey yapmamız gerekiyor:

  • Bağımlılık enjeksiyonu için kayıt olun;
  • AutoMapper'a sınıf haritalarının nasıl kullanılacağını anlatan bir sınıf oluşturun.

Her şeyden önce, Başlangıç ​​sınıfını açın. ConfigureServices yönteminde, son satırdan sonra aşağıdaki kodu ekleyin:

services.AddAutoMapper ();

Bu çizgi, AutoMapper'ın gerekli bağımlılık yapılandırmalarını yönetir, örneğin bağımlılık enjeksiyonuna kaydetmek ve başlangıçta eşleme profillerini yapılandırmak için uygulamayı taramak gibi.

Şimdi, kök dizine, Mapping adında yeni bir klasör ekleyin, ardından ModelToResourceProfile adlı bir sınıf ekleyin. Kodu bu şekilde değiştirin:

Sınıf, AutoMapper'ın haritalarımızın nasıl çalışacağını kontrol etmek için kullandığı bir sınıf türü olan Profile devralır. Yapıcıda, Category model sınıfı ile CategoryResource sınıfı arasında bir harita oluşturuyoruz. Sınıfların özellikleri aynı isim ve türlere sahip olduğundan, onlar için özel bir konfigürasyon kullanmamız gerekmez.

Son adım, nesneler eşlememizi işlemek için AutoMapper kullanmak için kategori denetleyicisini değiştirmekten ibarettir.

Bir IMapper uygulaması örneği almak üzere yapıcıyı değiştirdim. AutoMapper haritalama yöntemlerini kullanmak için bu arayüz yöntemlerini kullanabilirsiniz.

Ayrıca, GetAllAsync yöntemini değiştirerek, kategorilerin sıralanmasını Harita yöntemini kullanarak kaynakların sıralanmasına eşlemek için değiştirdim. Bu yöntem, eşlemek istediğimiz sınıf veya koleksiyonun bir örneğini alır ve genel tür tanımlarıyla, hangi tür sınıf veya koleksiyonun eşlenmesi gerektiğini tanımlar.

Hizmet sınıfını veya havuzunu adapte etmek zorunda kalmadan, sadece kurucuya yeni bir bağımlılık (IMapper) ekleyerek uygulamayı kolayca değiştirdiğimize dikkat edin.

Bağımlılık enjeksiyonu, özellikler eklemek veya kaldırmak için tüm kod uygulamalarınızı ihlal etmeniz gerekmediğinden uygulamanızı bakım kolaylığı ve değiştirilmesini sağlar.

Muhtemelen sadece denetleyici sınıfının değil, bağımlılık alan tüm sınıfların (bağımlılıklar da dahil) ciltleme yapılandırmalarına göre doğru sınıfları almak için otomatik olarak çözüldüğünü fark ettiniz.

Bağımlılık enjeksiyonu şaşırtıcı, değil mi?

Şimdi, dotnet run komutunu kullanarak API'yi tekrar başlatın ve yeni JSON yanıtını görmek için http: // localhost: 5000 / api / category adresine gidin.

Bu görmeniz gereken cevap verisidir.

Şimdiden GET bitiş noktamız var. Şimdi, POST (oluştur) kategorileri için yeni bir uç nokta oluşturalım.

9. Adım - Yeni Kategoriler Oluşturma

Kaynak yaratma ile uğraşırken aşağıdakiler gibi birçok şeye dikkat etmeliyiz:

  • Veri doğrulama ve veri bütünlüğü;
  • Kaynak yaratma yetkisi;
  • Hata işleme;
  • Kerestecilik.

Bu eğiticide kimlik doğrulama ve yetkilendirme ile nasıl başa çıkılacağını göstermeyeceğim, ancak bu özellikleri JSON web belirteci kimlik doğrulamasında yazıcımı okuyarak kolayca nasıl uygulayabileceğinizi görebilirsiniz.

Ayrıca, uygulamalarınızda kullanabileceğiniz güvenlik ve kullanıcı kaydı ile ilgili yerleşik çözümler sunan ASP.NET Identity adlı çok popüler bir çerçeve var. Kullanabileceğiniz dahili IdentityDbContext gibi EF Core ile çalışacak sağlayıcıları içerir. Burada daha fazla bilgi edinebilirsiniz.

Diğer senaryoları kapsayacak bir HTTP POST bitiş noktası yazalım (günlüğe kaydetme dışında, farklı kapsamlara ve araçlara göre değişebilen).

Yeni bitiş noktasını oluşturmadan önce, yeni bir kaynağa ihtiyacımız var. Bu kaynak, istemci uygulamalarının bu son noktaya (bu durumda kategori adı) gönderdiğimiz verileri uygulamamızın sınıfına eşler.

Yeni bir kategori oluşturduğumuzdan, henüz bir kimliğimiz yok ve bu yalnızca adını içeren bir kategoriyi temsil eden bir kaynağa ihtiyacımız olduğu anlamına geliyor.

Kaynaklar klasörüne SaveCategoryResource adlı yeni bir sınıf ekleyin:

Name özelliği üzerinde uygulanan Gerekli ve MaxLength niteliklerine dikkat edin. Bu niteliklere veri ek açıklamaları denir. ASP.NET Çekirdek boru hattı, istek ve yanıtları doğrulamak için bu meta verileri kullanır. Adlarından da anlaşılacağı gibi, kategori adı zorunludur ve maksimum 30 karakter uzunluğundadır.

Şimdi yeni API bitiş noktasının şeklini tanımlayalım. Kategoriler denetleyicisine aşağıdaki kodu ekleyin:

Çerçeveye HttpPost özniteliğini kullanarak bunun bir HTTP POST bitiş noktası olduğunu söylüyoruz.

Bu yöntemin yanıt türüne dikkat edin, Görev . Denetleyici sınıflarında bulunan yöntemlere eylemler denir ve bu imzası vardır, çünkü uygulama eylemi gerçekleştirdikten sonra birden fazla olası sonuç verebiliriz.

Bu durumda, kategori adı geçersizse veya bir şeyler ters giderse, genellikle istemci uygulamalarının sorunu tedavi etmek için kullanabileceği bir hata mesajı içeren 400 kodlu (hatalı istek) bir yanıt döndürmeliyiz veya Her şey yolunda giderse verilerle 200 yanıt (başarı).

Yanıt olarak kullanabileceğiniz birçok eylem türü vardır, ancak genellikle bu arayüzü kullanabiliriz ve ASP.NET Core bunun için varsayılan bir sınıf kullanır.

FromBody özelliği, ASP.NET Core'a istek gövdesi verilerini yeni kaynak sınıfımıza ayrıştırmasını söyler. Bu, kategori adını içeren bir JSON uygulamamıza gönderildiğinde, çerçevenin otomatik olarak yeni sınıfa ayrıştırılacağı anlamına gelir.

Şimdi rota mantığımızı uygulayalım. Yeni bir kategori oluşturmak için başarılı bir şekilde bazı adımları izlememiz gerekiyor:

  • İlk olarak, gelen isteği doğrulamamız gerekiyor. İstek geçersizse, hata mesajlarını içeren kötü bir istek yanıtı döndürmemiz gerekir;
  • Daha sonra, istek geçerliyse, AutoMapper kullanarak yeni kaynağımızı kategori model sınıfımızla eşlemeliyiz;
  • Şimdi yeni kategorimizi kaydetmemizi söyleyerek hizmetimizi aramamız gerekiyor. Eğer kaydetme mantığı problemsizce yürütülürse, yeni kategori verilerimizi içeren bir cevap döndürmelidir. Olmazsa, bize sürecin başarısız olduğuna dair bir gösterge ve olası bir hata mesajı vermelidir;
  • Sonunda, bir hata olursa, kötü bir istek döndürürüz. Değilse, yeni kategori modelimizi bir kategori kaynağına eşler ve yeni kategori verilerini içeren müşteriye başarılı bir yanıt veririz.

Karmaşık görünüyor, ancak API'mız için yapılandırdığımız hizmet mimarisini kullanarak bu mantığı uygulamak gerçekten çok kolay.

Gelen isteği doğrulayarak başlayalım.

Adım 10 - Model Halini Kullanarak İstek Organını Doğrulama

ASP.NET Çekirdek denetleyicileri, ModelState adlı bir özelliğe sahiptir. Bu özellik, işlem yürütmemize varmadan önce istek yürütme sırasında doldurulur. Bir ModelStateDictionary örneğidir, isteğin geçerli olup olmadığı ve olası doğrulama hata mesajları gibi bilgileri içeren bir sınıf.

Bitiş noktası kodunu aşağıdaki gibi değiştirin:

Kod, model durumunun (bu durumda, talep gövdesinde gönderilen verilerin) geçersiz olup olmadığını kontrol eder ve veri açıklamalarımızı kontrol eder. Değilse, API kötü bir istek (400 durum koduyla) ve ek açıklama meta verilerimiz tarafından sağlanan varsayılan hata iletilerini döndürür.

ModelState.GetErrorMessages () yöntemi henüz uygulanmadı. Doğrulama hatalarını istemciye geri döndürmek için basit dizelere dönüştürmek üzere uygulayacağım bir uzantı yöntemi (zaten var olan bir sınıf veya arabirimin işlevselliğini artıran bir yöntem).

API'mızın kök dizinine yeni bir uzantı ekledikten sonra yeni bir ModelStateExtensions sınıfı ekleyin.

Tüm uzatma yöntemleri, ilan edildiği sınıfların yanı sıra statik olmalıdır. Bu, belirli örnek verileri işlemedikleri ve uygulama başladığında yalnızca bir kez yüklendikleri anlamına gelir.

Parametre bildiriminin önündeki bu anahtar kelime, C # derleyicisine bir uzantı yöntemi olarak davranmasını söyler. Sonuç olarak bu sınıfı normal bir yöntem gibi adlandırabiliriz çünkü uzantıyı kullanmak istediğimiz yerde ilgili yönergeyi dahil ediyoruz.

Uzantı, .NET'in çok kullanışlı bir özelliği olan LINQ sorgularını kullanır; bu, zincirlenebilir ifadeler kullanarak verileri sorgulamamızı ve dönüştürmemizi sağlar. Buradaki ifadeler, doğrulama hatası yöntemlerini, hata mesajlarını içeren bir dizi listeye dönüştürür.

Bir sonraki adıma geçmeden önce Supermarket.API.Extensions ad alanını kategori denetleyicisine alın.

Supermarket.API.Extensions kullanarak;

Yeni kaynağımızı kategori model sınıfına eşleyerek son nokta mantığımızı uygulamaya devam edelim.

Adım 11 - Yeni Kaynağın Eşlenmesi

Modelleri kaynaklara dönüştürmek için zaten bir eşleme profili tanımladık. Şimdi tersini yapan yeni bir profile ihtiyacımız var.

Eşleme klasörüne yeni bir sınıf ResourceToModelProfile ekleyin:

Burada yeni bir şey yok. Bağımlılık enjeksiyonunun büyüsü sayesinde, AutoMapper uygulama başladığında bu profili otomatik olarak kaydeder ve kullanmak için başka bir yeri değiştirmek zorunda değiliz.

Şimdi yeni kaynağımızı ilgili model sınıfıyla eşleştirebiliriz:

Adım 12 - Tasarruf Mantığını Kullanmak İçin İstek-Yanıt Paterninin Uygulanması

Şimdi en ilginç mantığı uygulamak zorundayız: yeni bir kategori kaydetmek için. Hizmetimizin bunu yapmasını bekliyoruz.

Veritabanına bağlanırken ortaya çıkan sorunlar nedeniyle veya belki de herhangi bir şirket içi iş kuralı verilerimizi geçersiz kıldığı için tasarruf mantığı başarısız olabilir.

Bir şeyler ters giderse, basitçe bir hata yapamayız, çünkü API durdurabilir ve istemci uygulaması sorunun nasıl çözüleceğini bilemez. Ayrıca, potansiyel olarak hatayı kaydeden bazı kayıt mekanizmalarına sahip oluruz.

Tasarruf yönteminin sözleşmesi, yöntemin ve yanıt türünün imzasının, işlemin doğru yürütüldüğünü bize bildirmesi gerektiği anlamına gelir. İşlem devam ederse, kategori verilerini alırız. Olmazsa, en azından sürecin neden başarısız olduğunu belirten bir hata mesajı almalıyız.

İstek-cevap modelini uygulayarak bu özelliği uygulayabiliriz. Bu kurumsal tasarım kalıbı, bazı görevlerin yerine getirilmesi ve hizmetin kullanıldığı sınıfa bilgi döndürülmesi için hizmetlerimizin kullanacağı bilgileri kapsama yolu olarak, istek ve yanıt parametrelerimizi sınıflara yerleştirir.

Bu kalıp bize aşağıdakiler gibi bazı avantajlar sağlar:

  • Daha fazla parametre almak için hizmetimizi değiştirmemiz gerekirse, imzasını atmamız gerekmez;
  • İsteğimiz ve / veya yanıtlarımız için standart bir sözleşme tanımlayabiliriz;
  • İş mantığını ve olası başarısızlıkları, başvuru sürecini durdurmadan halledebiliriz ve tonlarca deneme toplama bloğu kullanmamız gerekmez.

Veri değişikliklerini işleyen hizmet yöntemlerimiz için standart bir yanıt türü oluşturalım. Bu türden her istek için isteğin sorunsuz bir şekilde gerçekleştirilip gerçekleştirilmediğini bilmek istiyoruz. Başarısız olursa, istemciye bir hata mesajı döndürmek istiyoruz.

Etki alanı klasöründe, Hizmetler'in içine, İletişim adlı yeni bir dizin ekleyin. BaseResponse adında yeni bir sınıf ekleyin.

Bu, yanıt türlerimizin devralacağı soyut bir sınıftır.

Soyutlama, isteklerin başarıyla tamamlanıp tamamlanmadığını söyleyen bir Başarı özelliğini ve bir şey başarısız olursa hata iletisine sahip olan bir Message özelliğini tanımlar.

Bu özelliklerin gerekli olduğuna ve yalnızca kalıtsal sınıfların bu verileri ayarlayabildiğine dikkat edin, çünkü çocuk sınıflar bu bilgileri yapıcı işlevden geçirmek zorundadır.

İpucu: Her şey için temel sınıfları tanımlamak iyi bir uygulama değildir, çünkü temel sınıflar kodunuzu birleştirir ve kolayca değiştirmenizi önler. Kalıtım üzerinde kompozisyon kullanmayı tercih eder.
Bu API'nin kapsamı için, temel sınıfları kullanmak gerçekten sorun değil, çünkü hizmetlerimiz fazla büyümeyecek. Bir hizmet veya uygulamanın sık sık büyüyüp değişeceğini fark ederseniz, bir temel sınıf kullanmaktan kaçının.

Şimdi, aynı klasöre SaveCategoryResponse adlı yeni bir sınıf ekleyin.

Yanıt türü, istek başarıyla tamamlanırsa kategori verilerimizi içerecek bir Kategori özelliği de belirler.

Bu sınıf için üç farklı kurucu tanımladığımı fark et:

  • Başarı ve mesaj parametrelerini temel sınıfa geçirecek ve ayrıca Kategori özelliğini belirleyen özel bir tane;
  • Parametre olarak yalnızca kategoriyi alan bir yapıcı. Bu, başarılı bir cevap oluşturarak, ilgili kurucuları ayarlamak için özel kurucuyu çağırır;
  • Yalnızca iletiyi belirten üçüncü bir yapıcı. Bu bir başarısızlık yanıtı oluşturmak için kullanılacaktır.

C #, çoklu yapıcıları desteklediğinden, yalnızca farklı yapıcılar kullanarak, bununla başa çıkmak için farklı yöntemler tanımlamaksızın yanıt oluşturmayı basitleştirdik.

Artık yeni kaydetme metodu sözleşmesini eklemek için servis arayüzümüzü değiştirebiliriz.

ICategoryService arayüzünü aşağıdaki gibi değiştirin:

Bu yönteme yalnızca bir kategoriyi geçeceğiz ve model verilerini kaydetmek için gerekli tüm mantığı ele alacak, bunu yapmak için depoları ve diğer gerekli hizmetleri düzenleyecektir.

Uyarı Bu görevi gerçekleştirmek için başka parametrelere ihtiyacımız olmadığından burada belirli bir istek sınıfı oluşturmuyorum. Bilgisayar programlamasında KISS adı verilen bir kavram var - Basit Tutun, Aptalca. Temel olarak, başvurunuzu mümkün olduğunca basit tutmanız gerektiğini söylüyor.

Uygulamalarınızı tasarlarken bunu unutmayın: yalnızca bir sorunu çözmek için ihtiyaç duyduğunuz şeyi uygulayın. Başvurunuzu fazla değiştirmeyin.

Artık bitiş noktası mantığımızı bitirebiliriz:

İstek verilerini doğruladıktan ve kaynağı modelimize eşleştirdikten sonra, verileri devam ettirmek için hizmetimize aktarıyoruz.

Bir şey başarısız olursa, API hatalı bir istek döndürür. Aksi takdirde, API yeni kategoriyi (şimdi yeni Id gibi verileri de içeren) önceden yarattığımız CategoryResource ile eşleştirir ve müşteriye gönderir.

Şimdi hizmet için gerçek mantığı uygulayalım.

Adım 13 - Veri Tabanı Mantığı ve Çalışma Deseni Birimi

Veriyi veritabanında saklayacağımızdan, havuzumuzda yeni bir yönteme ihtiyacımız var.

ICategoryRepository arabirimine yeni bir AddAsync yöntemi ekleyin:

Şimdi bu yöntemi gerçek depo sınıfımızda uygulayalım:

Burada setimize yeni bir kategori ekliyoruz.

Bir DBSet <> sınıfına eklediğimizde, EF Core modelimizde meydana gelen tüm değişiklikleri izlemeye başlar ve bu verileri mevcut durumda kullanarak model ekleyecek, güncelleyecek veya silecek sorgular oluşturmak için kullanır.

Mevcut uygulama modeli basitçe setimize ekliyor, ancak verilerimiz hala kurtarılmıyor.

Bağlam sınıfında bulunan ve sorguları veritabanına gerçekten uygulamak için çağırmamız gereken SaveChanges adlı bir yöntem var. Burada bir arama yapmadım çünkü bir depo veriye dayanmamalı, bu sadece bellekteki bir nesne koleksiyonudur.

Bu konu, deneyimli .NET geliştiricileri arasında bile çok tartışmalıdır, ancak depo sınıflarında neden SaveChanges'i aramamanız gerektiğini size açıklamama izin verin.

Bir havuzu kavramsal olarak .NET çerçevesindeki diğer herhangi bir koleksiyon olarak düşünebiliriz. .NET'teki (ve Javascript ve Java gibi diğer birçok programlama dili) bir koleksiyonla uğraşırken, genellikle:

  • Yeni öğeler ekleyin (verileri listeleri, dizileri ve sözlükleri zorladığınızda olduğu gibi);
  • Öğeleri bulun veya filtreleyin;
  • Bir öğeyi koleksiyondan kaldırın;
  • Belirli bir öğeyi değiştirin veya güncelleyin.

Gerçek dünyadan bir liste düşünün. Bir süpermarkette bir şeyler satın almak için bir alışveriş listesi yazdığınızı hayal edin (ne tesadüf, hayır?).

Listede, satın almanız gereken tüm meyveleri yazarsınız. Bu listeye meyve ekleyebilir, satın almaktan vazgeçerseniz bir meyveyi kaldırabilir veya bir meyvenin adını değiştirebilirsiniz. Ancak meyveleri listeye kaydedemezsiniz. Basit bir İngilizce dilinde böyle bir şey söylemek mantıklı değil.

İpucu: Nesne yönelimli programlama dillerinde sınıflar ve arabirimler tasarlarken, yaptığınız şeyin doğru olup olmadığını kontrol etmek için doğal dili kullanmayı deneyin.
Örneğin, bir insanın bir insan arayüzü oluşturduğunu söylemek mantıklıdır, ancak bir erkeğin bir hesap uyguladığını söylemek mantıklı değildir.

Eğer meyve listelerini “kaydetmek” istiyorsanız (bu durumda, tüm meyveleri almak için), bunu ödersiniz ve süpermarket bir tedarikçiden daha fazla meyve almak zorunda olup olmadıklarını kontrol etmek için stok verilerini işler.

Programlama yaparken aynı mantık uygulanabilir. Havuzlar verileri kaydetmemeli, güncellememeli veya silmemelidir. Bunun yerine, bu mantığı ele almak için onu farklı bir sınıfa devretmelidirler.

Verileri doğrudan depoya kaydederken başka bir sorun var: işlemleri kullanamazsınız.

Uygulamamızın, bazı kullanıcı adlarını saklayan bir kayıt mekanizmasına sahip olduğunu ve API verilerinde her değişiklik yapıldığında yapılan eylemin olduğunu düşünün.

Şimdi, bir nedenden ötürü, kullanıcı adını güncelleyen bir servisi aradığınızı hayal edin (bu genel bir senaryo değildir, ancak onu düşünelim).

Kullanıcı adını kurgusal bir kullanıcı tablosunda değiştirmek için, bu işlemi kimin yaptığını doğru bir şekilde söylemek için ilk önce tüm kayıtları güncellemelisiniz, değil mi?

Şimdi, kullanıcılar için güncelleme yöntemini uyguladığımızı ve farklı depolarda oturum açtığımızı ve her ikisinin de SaveChanges'i çağırdığını hayal edin. Bu yöntemlerden biri güncelleme işleminin ortasında başarısız olursa ne olur? Veri tutarsızlığına sahip olacaksınız.

Değişikliklerimizi veritabanına ancak her şey bittikten sonra kaydetmeliyiz. Bunu yapmak için, çoğu veritabanının yalnızca karmaşık bir işlem bittikten sonra verileri kaydetmek için uyguladığı bir özellik olan bir işlem kullanmalıyız.

“- Tamam, peki burada bir şeyleri kurtaramazsak, nerede yapmalıyız?”

Bu konuyu ele almak için ortak bir kalıp, Çalışma Kalıbı Birimidir. Bu kalıp, AppDbContext örneğimizi bir bağımlılık olarak alan ve işlemleri başlatma, tamamlama veya iptal etme yöntemlerini ortaya çıkaran bir sınıftan oluşur.

Burada sorunumuza yaklaşmak için basit bir çalışma birimi uygulaması kullanacağız.

IUnitOfWork adlı Etki Alanı katmanının Havuzları klasörüne yeni bir arayüz ekleyin:

Gördüğünüz gibi, yalnızca veri yönetimi işlemlerini eşzamansız olarak tamamlayacak bir yöntem ortaya koyuyor.

Şimdi gerçek uygulamayı ekleyelim.

Persistence katmanının RepositoriesRepositories klasörüne UnitOfWork adlı yeni bir sınıf ekleyin:

Bu, depolarınızı kullanarak düzenlemeyi bitirdikten sonra tüm değişiklikleri yalnızca veritabanına kaydedecek olan basit ve temiz bir uygulamadır.

İş Birimi modelinin uygulamalarını araştırırsanız, geri alma işlemleri uygulayan daha karmaşık olanları bulacaksınız.

EF Core, depo desenini ve çalışma birimini sahnelerin arkasına zaten uyguladığı için, geri alma yöntemini dikkate almamız gerekmez.

" - Ne? Peki neden tüm bu arayüzleri ve sınıfları oluşturmak zorundayız? ”

Kalıcılık mantığını iş kurallarından ayırmak, kodun tekrar kullanılabilirliği ve bakımı açısından birçok avantaj sağlar. Doğrudan EF Core kullanıyorsak, değiştirmesi o kadar kolay olmayacak daha karmaşık sınıflara sahip olacağız.

Gelecekte, ORM çerçevesini Dapper gibi farklı bir sistemle değiştirmeye karar verdiğinizi ya da performans nedeniyle düz SQL sorguları uygulamak zorunda kaldığınızı hayal edin. Sorgu mantığınızı hizmetlerinize bağlarsanız, mantığı değiştirmek zor olacaktır, çünkü bunu birçok sınıfta yapmanız gerekecektir.

Havuz modelini kullanarak yeni bir havuz sınıfı uygulayabilir ve bağımlılık enjeksiyonunu kullanarak bağlayabilirsiniz.

Bu nedenle, temel olarak, eğer EF Core'u doğrudan hizmetlerinize kullanıyorsanız ve bir şeyi değiştirmeniz gerekiyorsa, elde edeceğiniz şey budur:

Dediğim gibi, EF Core, sahne arkasındaki İş Birimi ve Depo modellerini uygular. DbSet <> özelliklerimizi depo olarak düşünebiliriz. Ayrıca, SaveChanges, tüm veritabanı işlemlerinde başarılı olması durumunda yalnızca verilere devam eder.

Artık bir işin ne olduğunu ve neden depolarla kullandığınızı bildiğinize göre, gerçek hizmetin mantığını uygulayalım.

Dekuplaj mimarimiz sayesinde, bu sınıfa bağımlılık olarak UnitOfWork örneğini iletebiliriz.

İş mantığımız oldukça basit.

Önce yeni kategoriyi veritabanına eklemeye çalışırız, sonra API her şeyi bir try-catch bloğuna sararak kaydetmeye çalışır.

Bir şey başarısız olursa, API bazı kurgusal kayıt hizmetini çağırır ve başarısızlık gösteren bir cevap döndürür.

İşlem sorunsuz bir şekilde tamamlanırsa, uygulama kategori verilerini göndererek başarılı bir yanıt verir. Basit değil mi?

İpucu: Gerçek dünya uygulamalarında, her şeyi genel bir try-catch bloğu içine sarmamalısınız, bunun yerine olası tüm hataları ayrı ayrı ele almalısınız.
Basitçe bir try-catch bloğu eklemek, olası başarısız senaryoların çoğunu kapsamaz. Aletin hata işlemesini düzelttiğinizden emin olun.

API'mızı test etmeden önceki son adım, iş arayüzü birimini ilgili sınıfa bağlamaktır.

Bu yeni satırı, Başlangıç ​​sınıfının ConfigureServices yöntemine ekleyin:

services.AddScoped  ();

Şimdi test edelim!

Adım 14 - Postacı kullanarak POST Uç Noktamızı test etme

Dotnet run'ı kullanarak uygulamamızı tekrar başlatın.

Bir POST uç noktasını test etmek için tarayıcıyı kullanamıyoruz. Bitiş noktalarımızı test etmek için Postman'ı kullanalım. RESTful API'leri test etmek için çok yararlı bir araçtır.

Postacı'yı açın ve tanıtım mesajlarını kapatın. Bunun gibi bir ekran göreceksiniz:

Bitiş noktalarını test etmek için seçenekleri gösteren ekran

Seçili olan GET'i varsayılan olarak seçim kutusuna POST olarak değiştirin.

API adresini, İstek URL'sini girin alanına yazın.

API’mıza gönderilmek üzere talep kuruluşu verilerini sağlamalıyız. Gövde menü öğesine tıkladıktan sonra, altında gösterilen seçeneği ham olarak değiştirin.

Postacı sağ tarafta bir Metin seçeneği gösterecektir. JSON'a (application / json) değiştirin ve aşağıdaki JSON verilerini aşağıya yapıştırın:

{
  "ad": ""
}
Bir istek göndermeden hemen önce ekran

Gördüğünüz gibi, yeni bitiş noktamıza boş bir ad dizesi göndereceğiz.

Gönder düğmesine tıklayın. Bunun gibi bir çıktı alacaksınız:

Gördüğünüz gibi, doğrulama mantığımız işe yarıyor!

Bitiş noktası için oluşturduğumuz doğrulama mantığını hatırlıyor musunuz? Bu çıktı çalıştığının kanıtı!

Ayrıca sağda gösterilen 400 durum koduna dikkat edin. BadRequest sonucu bu durum kodunu otomatik olarak yanıta ekler.

Şimdi yeni cevabı görmek için JSON verilerini geçerli bir veri ile değiştirelim:

Sonunda, beklenen sonucu almamız bekleniyor

API, yeni kaynağımızı doğru bir şekilde oluşturdu.

Şimdiye kadar API'mız kategorileri listeleyip yaratabilir. API'lerinizi yapılandırmak için C # dili, ASP.NET Core çerçevesi ve genel tasarım yaklaşımları hakkında birçok şey öğrendiniz.

Kategorileri güncellemek için son nokta oluşturan kategoriler API’mize devam edelim.

Bundan sonra, size çoğu kavramı açıkladığımdan, açıklamaları hızlandıracağım ve zamanınızı boşa harcamamak için yeni konulara odaklanacağım. Hadi gidelim!

Adım 15 - Kategorileri Güncelleme

Kategorileri güncellemek için bir HTTP PUT uç noktasına ihtiyacımız var.

Kodlamamız gereken mantık POST'a çok benziyor:

  • Öncelikle, ModelState'i kullanarak gelen isteği doğrulamamız gerekiyor;
  • Eğer istek geçerliyse, API AutoMapper kullanarak gelen kaynağı bir model sınıfıyla eşlemelidir;
  • Ardından, kategoriyi güncellemesini, ilgili kategori kimliğini ve güncellenmiş verileri sağlayarak hizmetimizi aramamız gerekir;
  • Veritabanında verilen Id ile kategori yoksa, hatalı bir istek döndürürüz. Bunun yerine bir NotFound sonucu kullanabiliriz, ancak istemci uygulamalarına bir hata mesajı verdiğimiz için bu kapsam için gerçekten önemli değil;
  • Kaydetme mantığı doğru bir şekilde yürütülürse, servis güncellenen kategori verilerini içeren bir yanıt döndürmelidir. Olmazsa, bize sürecin başarısız olduğuna dair bir gösterge ve nedenini belirten bir mesaj vermelidir;
  • Son olarak, bir hata varsa, API kötü bir istek döndürür. Değilse, güncellenmiş kategori modelini bir kategori kaynağına eşler ve istemci uygulamasına başarılı bir yanıt verir.

Yeni PutAsync yöntemini controller sınıfına ekleyelim:

POST mantığıyla karşılaştırırsanız, burada sadece bir farkımız olduğunu fark edeceksiniz: HttPut niteliği, verilen rotanın alması gereken bir parametreyi belirtir.

Bu kategoriyi, / api / category / 1 gibi, son URL parçası olarak Id kategorisini belirterek arayacağız. ASP.NET Core boru hattı, bu parçayı aynı adın parametresine göre ayrıştırır.

Şimdi UpdateAsync yöntem imzasını ICategoryService arabiriminde tanımlamamız gerekiyor:

Şimdi gerçek mantığa geçelim.

Adım 16 - Güncelleme Mantığı

Kategorimizi güncellemek için önce mevcut verileri veritabanından döndürmemiz gerekir. Ayrıca, DBSet <> ’mize güncellememiz gerekir.

ICategoryService arayüzümüze iki yeni yöntem sözleşmesi ekleyelim:

Veritabanından eşzamanlı olmayan bir kategori döndürecek FindByIdAsync yöntemini ve Güncelleme yöntemini tanımladık. Güncelleme yönteminin eşzamanlı olmadığına dikkat edin çünkü EF Core API, modelleri güncellemek için eşzamansız bir yöntem gerektirmez.

Şimdi gerçek mantığı CategoryRepository sınıfına uygulayalım:

Sonunda servis mantığını kodlayabiliriz:

API, kategoriyi veritabanından almaya çalışır. Sonuç null olursa, kategorinin mevcut olmadığını belirten bir yanıt döndürürüz. Kategori varsa, yeni adını belirlememiz gerekir.

API, yeni bir kategori oluşturduğumuz gibi değişiklikleri kaydetmeye çalışır. İşlem tamamlanırsa, servis başarılı bir yanıt verir. Aksi takdirde, kayıt mantığı çalıştırılır ve bitiş noktası bir hata mesajı içeren bir yanıt alır.

Şimdi test edelim. Öncelikle, kullanmak için geçerli bir kimliğe sahip olmak için yeni bir kategori ekleyelim. Veri tabanımıza yerleştirdiğimiz kategorilerin tanımlayıcılarını kullanabiliriz, ancak API’nizin doğru kaynağı güncelleyeceğini göstermek için bu şekilde yapmak istiyorum.

Uygulamayı tekrar çalıştırın ve Postman'ı kullanarak, veritabanına yeni bir kategori POST:

Daha sonra güncellemek için yeni bir kategori ekleme

Elinde geçerli bir Kimlik bilgisine sahip olmak için, POST seçeneğini PUT olarak seçim kutusuna getirin ve URL'nin sonuna ID değerini ekleyin. Name özelliğini farklı bir adla değiştirin ve sonucu kontrol etmek için istek gönderin:

Kategori verileri başarıyla güncellendi

Kategori adını doğru şekilde düzenlediğinizden emin olmak için API bitiş noktasına bir GET isteği gönderebilirsiniz:

Bu şimdi bir GET isteğinin sonucudur

Kategoriler için uygulamamız gereken son işlem, kategorilerin hariç tutulmasıdır. Bir HTTP Silme bitiş noktası oluşturarak yapalım.

Adım 17 - Kategorileri Silme

Kategoriler silmek için mantığı uygulamak gerçekten çok kolay çünkü ihtiyaç duyduğumuz çoğu yöntem daha önce yapıldı.

Rotamızın çalışması için gerekli adımlar şunlardır:

  • API'nin servisimizi araması, kategorimizi silmesini söylemesi ve ilgili kimliği sağlaması gerekir;
  • Veritabanında verilen kimliğe sahip bir kategori yoksa, servis bunu gösteren bir mesaj döndürmelidir;
  • Silme mantığı sorunsuz bir şekilde yürütülürse, servis silinmiş kategori verilerimizi içeren bir yanıt döndürmelidir. Olmazsa, bize sürecin başarısız olduğuna dair bir gösterge ve olası bir hata mesajı vermelidir;
  • Son olarak, bir hata varsa, API kötü bir istek döndürür. Değilse, API güncellenmiş kategoriyi bir kaynakla eşleştirir ve müşteriye başarılı bir yanıt verir.

Yeni bitiş noktası mantığını ekleyerek başlayalım:

HttpDelete niteliği ayrıca bir kimlik şablonu tanımlar.

DeleteAsync imzasını ICategoryService arayüzümüze eklemeden önce küçük bir yeniden düzenleme işlemi yapmamız gerekir.

Yeni hizmet yöntemi, PostAsync ve UpdateAsync yöntemlerinde yaptığımız gibi, kategori verilerini içeren bir yanıt döndürmelidir. SaveCategoryResponse'ı bu amaç için yeniden kullanabiliriz, ancak bu durumda verileri kaydetmiyoruz.

Bu gereksinimi karşılayacak şekilde aynı şekilde yeni bir sınıf oluşturmaktan kaçınmak için, SaveCategoryResponse 'ı CategoryResponse olarak değiştirebiliriz.

Visual Studio Kodunu kullanıyorsanız, SaveCategoryResponse sınıfını açabilir, fare imlecini sınıf adının üzerine getirebilir ve sınıfı yeniden adlandırmak için Tüm Olayları Değiştir seçeneğini kullanabilirsiniz:

Tüm dosyalarda adı değiştirmenin kolay yolu

Dosya adını da yeniden adlandırdığınızdan emin olun.

DeleteAsync yöntem imzasını ICategoryService arabirimine ekleyelim:

Silme mantığını uygulamadan önce, havuzumuzda yeni bir yönteme ihtiyacımız var.

Kaldır yöntemi imzasını ICategoryRepository arabirimine ekleyin:

void Kaldır (Kategori kategorisi);

Ve şimdi depo sınıfındaki gerçek uygulamayı ekleyin:

EF Core, bir Kimliği silmek yerine hangi modeli sildiğimizi doğru bir şekilde anlamak için modelimizin örneğinin Kaldır yöntemine geçirilmesini gerektirir.

Son olarak, mantığı CategoryService sınıfına uygulayalım:

Burada yeni bir şey yok. Hizmet kategoriyi ID'ye göre bulmaya çalışır ve ardından kategoriyi silmek için havuzumuzu arar. Son olarak, iş birimi, asıl işlemi veritabanında gerçekleştiren işlemi tamamlar.

“- Hey, peki ya her kategorinin ürünleri? Hatalardan kaçınmak için önce bir havuz oluşturmanıza ve ürünleri silmenize gerek yok mu? ”

Cevap hayır. EF Core izleme mekanizması sayesinde, veritabanından bir model yüklediğimizde, çerçeve modelin hangi ilişkilere sahip olduğunu bilir. Silersek, EF Core ilk önce ilgili tüm modelleri tekrar tekrar silmesi gerektiğini bilir.

Sınıflarımızı veritabanı tablolarıyla eşleştirirken bu özelliği devre dışı bırakabiliriz, ancak bu eğitimin kapsamı dışındadır. Bu özellik hakkında bilgi edinmek istiyorsanız buraya bir göz atın.

Şimdi yeni uç noktamızı test etme zamanı. Uygulamayı tekrar çalıştırın ve aşağıdaki gibi Postman kullanarak bir DELETE isteği gönderin:

Gördüğünüz gibi, API mevcut kategoriyi problemsiz silmiş

Bir GET isteği göndererek API’nizin doğru çalıştığını kontrol edebiliriz:

Şimdi sonuç olarak sadece bir kategori alıyoruz

Kategoriler API’sini bitirdik. Şimdi ürünlerin API'sine geçme zamanı.

Adım 18 - Ürünler API'si

Şimdiye kadar ASP.NET Core ile CRUD işlemlerini gerçekleştirmek için tüm temel HTTP fiillerinin nasıl uygulanacağını öğrendiniz. Ürünler API'mızı uygulayarak bir sonraki seviyeye geçelim.

Tüm HTTP fiillerini tekrar ayrıntılandırmayacağım, çünkü ayrıntılı olacaktır. Bu eğitimin son bölümü için, veri tabanından veri sorgularken ilgili varlıkları nasıl dahil edeceğinizi ve EUnitOfMeasurement numaralandırma değerleri için tanımladığımız Açıklama niteliklerini nasıl kullanacağınızı göstermek için yalnızca GET isteğini ele alacağım.

ProductsController adlı Denetleyiciler klasörüne yeni bir denetleyici ekleyin.

Buradaki herhangi bir şeyi kodlamadan önce, ürün kaynağını yaratmalıyız.

Kaynağımızın nasıl görünmesi gerektiğini gösteren hafızanızı yenilememe izin verin:

{
 [
  {
   "kimliği": 1,
   "isim": "Şeker",
   "miktarInPackage": 1,
   "unitOfMurement": "KG"
   "kategori": {
   "kimliği": 3,
   "isim": "Şeker"
   }
  },
  … // Diğer ürünler
 ]
}

Veritabanındaki tüm ürünleri içeren bir JSON dizisi istiyoruz.

JSON verileri ürün modelinden iki şeye farklılık gösterir:

  • Ölçüm birimi daha kısa bir şekilde gösterilir, sadece kısaltmasını gösterir;
  • CategoryId özelliğini eklemeden kategori verilerini çıkarıyoruz.

Ölçü birimini temsil etmek için, enum türü yerine basit bir string özelliği kullanabiliriz (bu arada, JSON verileri için varsayılan bir enum türüne sahip değiliz, bu nedenle onu farklı bir türe dönüştürmeliyiz).

Şimdi yeni kaynağın nasıl şekillendiğine bakalım, yaratalım. Kaynaklar klasörüne yeni bir ProductResource sınıfı ekleyin:

Şimdi model sınıfı ile yeni kaynak sınıfımız arasındaki eşlemeyi yapılandırmamız gerekiyor.

Haritalama konfigürasyonu, diğer haritalamalar için kullanılanlarla neredeyse aynı olacaktır, fakat burada EUnitOfMeasurement enumumun bir dizgeye dönüşümünü ele almalıyız.

Numaralandırma türlerine uygulanan StringValue özniteliğini hatırlıyor musunuz? Şimdi size bu bilgiyi .NET framework'ün güçlü bir özelliğini kullanarak nasıl çıkaracağınızı göstereceğim: Reflection API.

Reflection API, meta verileri çıkarmamıza ve düzenlememize olanak tanıyan güçlü bir kaynak kümesidir. Pek çok çerçeve ve kitaplık (ASP.NET Core'un kendisi de dahil olmak üzere) bu kaynakları, sahne arkasındaki birçok şeyi işlemek için kullanır.

Şimdi pratikte nasıl çalıştığını görelim. EnumExtensions adlı Uzantılar klasörüne yeni bir sınıf ekleyin.

Şifreye ilk defa baktığınızda korkutucu görünebilir, ancak çok karmaşık değildir. Nasıl çalıştığını anlamak için kod tanımını çözelim.

İlk olarak, belirli bir enumu argüman olarak alan genel bir yöntem (bu durumda, TEnum bildirimi tarafından temsil edilen birden fazla argüman türü alabilen bir yöntem) tanımladık.

Enum, C # dilinde ayrılmış bir anahtar kelime olduğundan, geçerli bir ad yapmak için parametrenin adının önüne bir @ ekledik.

Bu yöntemin ilk çalıştırma adımı GetType yöntemini kullanarak parametrenin tür bilgisini (sınıf, arabirim, enum veya yapı tanımı) elde etmektir.

Ardından, yöntem GetField (@ enum.ToString ()) kullanarak belirli numaralandırma değerini (örneğin, Kilogram) alır.

Bir sonraki satır, numaralandırma değeri üzerine uygulanan tüm Description niteliklerini bulur ve verilerini bir dizide saklar (bazı durumlarda aynı özellik için birden fazla nitelik belirtebiliriz).

Son satır, numaralandırma türü için en az bir açıklama özelliğine sahip olup olmadığımızı kontrol etmek için daha kısa bir sözdizimi kullanır. Varsa, bu niteliğin sağladığı Açıklama değerini döndürürüz. Olmazsa, numaralandırmayı varsayılan döküm kullanarak bir dize olarak döndürürüz.

? işleci (boş koşullu işleç), özelliğine erişmeden önce değerin boş olup olmadığını kontrol eder.

?? operatör (boş bir birleştirici operatör), uygulamaya boş değilse değeri sola, aksi takdirde sağdaki değeri döndürmesini söyler.

Artık açıklamaları çıkarmak için bir uzatma yöntemimiz olduğuna göre, haritamızı model ve kaynak arasında yapılandıralım. AutoMapper sayesinde bunu sadece bir ekstra hatla yapabiliriz.

ModelToResourceProfile sınıfını açın ve kodu şu şekilde değiştirin:

Bu sözdizimi, AutoMapper'a EUnitOfMeasurement değerimizi tanımını içeren bir dizgeye dönüştürmek için yeni uzantı yöntemini kullanmasını söyler. Basit değil mi? Tam sözdizimini anlamak için resmi belgeleri okuyabilirsiniz.

Kategori özelliği için herhangi bir eşleme yapılandırması tanımlamadığımızı fark edin. Eşleştirmeyi daha önce kategoriler için yapılandırdığımızdan ve ürün modelinin aynı tür ve adda bir kategori özelliğine sahip olduğundan, AutoMapper, ilgili yapılandırmayı kullanarak eşlemesi gerektiğini dolaylı olarak bilir.

Şimdi bitiş noktası kodunu ekleyelim. ProductsController kodunu değiştirin:

Temel olarak, kategori denetleyicisi için tanımlanan aynı yapı.

Hizmet bölümüne gidelim. Etki Alanı katmanında bulunan Hizmetler klasörüne yeni bir IProductService arabirimi ekleyin:

Yeni hizmeti gerçekten uygulamadan önce bir havuza ihtiyacımız olduğunu anlamalıydın.

İlgili klasöre IProductRepository adlı yeni bir arayüz ekleyin:

Şimdi depoyu uygulayalım. Veri deposunda olduğu gibi her bir ürünün ilgili kategori verilerini döndürmemiz dışında, hemen hemen kategori havuzunda yaptığımız gibi uygulamak zorundayız.

EF Çekirdek, varsayılan olarak, veri sorgularken modellerinizle ilgili varlıkları içermez, çünkü çok yavaş olabilir (on ile ilgili varlıklar içeren bir model hayal edin).

Kategoriler verilerini dahil etmek için sadece bir ekstra satıra ihtiyacımız var:

Dahil Etme çağrısına dikkat edin (p => p.Category). Bu sözdizimini, veri sorgularken gereken sayıda varlık içerecek şekilde zincirleyebiliriz. EF Core, seçimi yaparken bunu bir birleştirmeye çevirecek.

Artık ProductService sınıfını kategoriler için yaptığımız gibi uygulayabiliriz:

Başlangıç ​​sınıfını değiştiren yeni bağımlılıkları bağlayalım:

Son olarak, API'yi test etmeden önce, uygulamayı başlatırken bazı ürünleri içerecek şekilde AppDbContext sınıfını değiştirelim, böylece sonuçları görelim:

Uygulamayı başlatırken onları tohumladığımız kategorilerle ilişkilendiren iki kurgusal ürün ekledim.

Test zamanı! API'yi tekrar çalıştırın ve Postman kullanarak / api / products'a bir GET isteği gönderin:

Voila İşte ürünlerimiz

Ve bu kadar! Tebrikler!

Artık, dekuplajlı bir mimari kullanarak ASP.NET Core kullanarak bir RESTful API oluşturma konusunda temeliniz var. Uygulamalarınızı tasarlarken kullanacağınız .NET Core çerçevesinin pek çok şeyini, C # ile nasıl çalışacağınızı, EF Core ve AutoMapper'ın temellerini ve birçok kullanışlı modeli öğrendiniz.

Github deposunu kontrol ederek, diğerleri için ürünler için diğer HTTP fiillerini içeren API uygulamasının tamamını kontrol edebilirsiniz:

Sonuç

ASP.NET Core, web uygulamaları oluştururken kullanılacak harika bir çerçevedir. Temiz, bakımı yapılabilir uygulamalar oluşturmak için kullanabileceğiniz birçok yararlı API ile birlikte gelir. Profesyonel uygulamalar oluştururken bunu bir seçenek olarak düşünün.

Bu makale profesyonel bir API'nin tüm yönlerini kapsamamıştır, ancak tüm temel hususları öğrendiniz. Ayrıca günlük olarak karşılaştığımız kalıpları çözmek için birçok kullanışlı kalıp öğrendiniz.

Umarım bu makaleyi beğenmişsinizdir ve umarım sizin için yararlı olmuştur. Bunu nasıl geliştirebileceğimi anlamak için görüşlerinizi takdir ediyorum.

Öğrenmeye Devam Referansları

.NET Çekirdek Öğreticiler - Microsoft Docs

ASP.NET Çekirdek Belgeleri - Microsoft Belgeleri