Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

gRPC’de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması

Merhaba,

Bir önceki gRPC Nedir? Ne Amaçla ve Nasıl Kullanılır? başlıklı makalemizde gRPC’nin ne olduğuna ve ne amaçla kullanıldığına teorik değinmiştik. Bu içeriğimizde ise gRPC ile client ve server uygulamalarının nasıl geliştirildiğini, servislerin ve mesaj türlerinin nasıl generate edildiğini, her iki uygulama arasında iletişimin nasıl sağlandığını ve gRPC’de ki temel yapıtaşı olan proto dosyalarının fiziksel olarak ne olduğunu inceleyeceğiz. Hadi gelin vakit kaybetmeden başlayalım.

gRPC Server Projesi Oluşturma

İlk olarak bir gRPC server projesi oluşturarak başlayalım.
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması
Malumunuz istifade edeceğimiz ortam Visual Studio 🙂 Dolayısıyla ‘gRPC Service’ seçerek platformumuzu belirtiyor ve ardından proje ismini belirtiyoruz.
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması
Eee artık framework olarak .NET 5.0‘da oluşturmak işin farzı oldu.

gRPC Server Proje Dosyalarını İnceleme

gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıOluşturulan gRPC server projesinin dosyalarını incelersek eğer görüldüğü üzere klasik .NET Core temellerinde bir projeyle karşılaşmaktayız. Sadece ekstradan ‘Protos’ klasörü ve altındaki ‘greet.proto’ dosyası gözümüze çarpmaktadır. Bu dosya, client ile server arasındaki kontrat işlevini üstlenecek olan ve içeriğimizin seyrinde daha detaylı ele alacağımız bir dosyadır. Şimdi her şeyden önce bir gRPC uygulamasının ‘Startup.cs’ dosyasını inceleyerek başlayalım.
Yandaki görselde bir gRPC projesinin ‘Startup.cs’ içeriğini gözlemlemekteyiz. Tarafımca vurgulanan iki noktaya nazarınızı çekmek istiyorum. İlki kırmızı ile vurguladığım services.AddGrpc() komutu ile servisin eklenmesi gerektiğidir. Evet, bir uygulamanın gRPC olması için bu şekilde servisin eklenmesi gerekmektedir. İkincisi ise yeşil ile vurguladığım ‘UseEndpoints’i içerisindeki endpoints.MapGrpcService() middleware’idir. Bu middleware ile server’ın aksiyonlarını belirlediği servis belirlenmiştir. Böylece client’tan bir metodu tetiklemek için gelen istek neticesinde o metodu hangi servisin karşılayacağı ve tetikleyeceği buradan bildirilmektedir. Bu servis proje dosyalarına göz atarsanız ‘Services’ klasörü içerisinde ‘GreeterService’ olarak tutulmaktadır. Velhasıl, bu servis meselesini içeriğimizin devamında daha da detaylandırmış olacağız. Şimdilik geçiyorum…

proto Dosyası İnceleme

gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıGelelim proto dosyasına. Ne demiştik, server ile client arasında kontratı proto dosyası ile sağlamaktayız. İçeriğine bakarsak eğer ‘service’ ve ‘message’ tanımlamaları olan ve ‘syntax’, ‘option’ ve ‘package’ gibi keywordler barındıran karman çorman bir dosya 🙂 Hiiççç panik yapmayın. Birazdan bu dosyayı ve içeriğindekilerin ne anlam ifade ettiğini adınız ve soyadınız gibi öğrenmiş olacaksınız.

İlk olarak dosyanın yukarısında tanımlanan keywordleri ele alalım. Sonra alttaki ‘service’ ve ‘message’ yapılarını inceleyecelim;

  • syntax
    Proto sürümünü ifade eder.
  • option
    Generate edilecek servis yapılanmasının oluşturulacağı namespace adını ifade eder.
  • package
    Generate edilecek servis dosyalarında kullanılacak paketleri ifade eder. Yani bildiğiniz kütüphanelerdir.
  • service
    Uygulamadaki generate edilecek servisin adını ve içerisindeki metot imzasını ifade etmektedir. Yani içeriksel açıdan oldukça önemlidir. Yukarıdaki örnek proto’da ki service yapılanmasını ele alırsak eğer;
    gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulmasışeklinde genel yapılanmayı izah edebiliriz. Buradan yola çıkarak genel prototipi de aşağıdaki gibi varsayabiliriz.
    gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması

    Proto dosyası servis prototipi…

  • message
    Client ile server arasındaki veri iletiminde kullanılacak mesaj türünü ifade etmektedir. Yukarıdaki örnek proto dosyasında ‘HelloRequest’ ve ‘HelloReply’ mesaj türlerine karşılık gelmektedir. İlgili türlerin içerisinde sırasıyla ‘string’ türde ‘name’ ve ‘message’ alanları mevcuttur. Yani bu demek oluyor ki, bu mesajlar içlerinde bu property’leri(C# dilinde) taşıyacaktırlar.

Bu şekilde bir service tasarımı esasında tek request’e tek response olduğundan dolayı Unary yöntemi olarak nitelendirilmektedir.

Tabi, oluşturulan bir gRPC uygulamasındaki bu ‘Greeter’ servisi örnek amaçlı oluşturulmuştur. Dolayısıyla özelleştirilebilmektedir. Sonraki içeriklerimizde servisleri ve mesaj türlerini yer yer özelleştirecek ve öylece pratikte inceliyor olacağız.

proto Dosyasının Derlenmesi – Servis ve Mesaj Türlerinin Generate Edilmesi

gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıVelhasıl, proto dosyası içerisinde tanımlanan servis ve mesaj türlerini generate edebilmek için uygulamanın derlenmesi gerekmektedir. Bu derleme neticesinde yanda görüldüğü üzere uygulamanın çıktılarından
'obj' -> 'Debug' -> 'net5.0' -> 'Protos'
kombinasyonuna gelirseniz eğer ilgili servise karşılık sınıfların oluşturulduğunu göreceksiniz.

Dikkat ederseniz eğer ‘Greater’ servisi ile birlikte ‘HelloRequest’ ve ‘HelloReply’ mesaj türleri oluşturulmuştur. Bu sınıflardan herhangi birine göz atarsak eğer;
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıGörüldüğü üzere generate edilen sınıf(Greeter) biraz ileri derecede dil yeteneği gerektirecek şekilde oluşturulmuştur. Bu generate edilen dosyalarda sürekli gözünüze çarpan ya da bir başka deyişle çarpacak olan global ve :: operatörlerinin ne olduğunu anlayabilmek için C#’ta :: Operatörü başlıklı yazıma göz atabilirsiniz. Doğrusu bu dosyaları esasında anlamak ve anlamlandırmak mecburiyetinde değilsiniz. Nihayetinde protoc compiler sayesinde generate edilmektedir ve üzerinde bile herhangi bir fiziksel değişiklik kalıcılık sergilemeyecektir. Dolayısıyla içerik açısından sizi pek ilgilendirmeyecek bu sınıfları sadece kullanmaya odaklı bir şekilde değerlendireceksiniz.

Generate Edilen Türlerin Kullanılması

Artık servis ile birlikte mesaj türleri oluşturulmuş olduğuna göre bunları kullanacak olan bir servis’in yaratılması gerekmektedir. Bunun için mimari bize ‘Services’ klasöründeki ‘GreeterService’ class’ını örnek olarak sunmaktadır. İlgili class’ı incelersek eğer;
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıYukarıdaki servis görseline dikkat ederseniz, oluşturulan servis’in ‘name[Base]’ şeklinde isimlendirilerek generate edilen bir class’tan inherit edildiğini görmekteyiz. Haliyle ilgili base class içerisinde proto dosyası sayesinde generate edilerek virtual olarak tanımlanmış olan ‘SayHello’ metodu override edilerek, gelecek istek neticesinde yapılacak operasyon gerçekleştirilmektedir.

gRPC Server Uygulamasının .csproj Dosyasının İncelenmesi

gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıgRPC Server uygulamasının .csproj dosyasına da göz atmakta fayda olacaktır. Haliyle yandaki görseli incelerseniz eğer, bir gRPC server uygulamasında olması gereken paketleri ve temel konfigürasyonları görebilmekteyiz. Dikkat ederseniz gRPC protoc compiler işlemlerini gerçekleştirebilmek için ‘Grpc.AspNetCore’ paketi referans edilmiştir. Ayrıca ‘Protobuf’ olarak ‘Protos\greet.proto’ bildirilmiş ve ‘GrpcServices’ özelliği de ‘Server’ olarak nitelendirilmiştir. Tabi ki de tüm proto dosyaları burada aynı şekilde bildirilmelidir.

gRPC Client Projesi Oluşturma

Artık sıra gRPC üzerinden server’a istek gönderebilmesi için client uygulamasının geliştirilmesine gelmiştir. Bunun için web, mobil, windows form yahut console platformlarından herhangi birini tercih edebilirsiniz. Biz bu içeriğimizde, örneklendirmeye pratiksel açıdan en yatkın olan console uygulaması üzerinden client oluşturmayı tercih edeceğiz.

Şimdi bu client uygulamasında ilk yapmamız gereken, server’da ki proto dosyasının birebir aynı içeriklisini oluşturmaktır. Nihayetinde server’la client’ın haberleşebilmesi için aralarındaki kontratı bu proto dosyaları sağlayacak ve her iki uygulamada da gerekli sınıf ve türlerin generate operasyonunu üstlenecektir.
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıGörüldüğü üzere ilgili proto dosyası ‘csharp_namespace’ değeri dışında hiçbir değişiklik yapılmaksızın oluşturulmuştur. Namespace değerinin değiştirilme sebebi ise client’a uygun bir isimlendirme yapılmasıdır. Eee o kadar da olacak artık 🙂

Peki hocam, console uygulamasında bu proto dosyasını ne ile compile edecek ve gerekli servis sınıf ve türlerini oluşturacağız? şeklindeki olası sorunuzu duyar gibiyim… Evet, haklı olarak gelen bu soruya karşı aşağıdaki yüklenmesi gereken kütüphaneleri cevap olarak verebiliriz.
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin OluşturulmasıEvet, görüldüğü üzere client uygulamasında Google.Protobuf, Grpc.Net.Client ve Grpc.Tools kütüphanelerinin yüklü olması gerekmektedir. Bu kütüphanelerin işlevsel sorumluluklarını sırasıyla izah edersek eğer;

  • Google.Protobuf
    Protobuf serialization ve deserialization işlemleri için gerekli kütüphanedir.
  • Grpc.Net.Client
    .NET mimarilerine uygun gRPC kütüphanesidir.
  • Grpc.Tools
    Proto dosyalarını derlemek için gerekli compiler’ı ve diğer araçları içeren kütüphanedir.

Ayrıca client’ın .csproj dosyasına dikkat ederseniz ilgili proto dosyası ‘Protobuf’ olarak eklenmiştir ve ‘GrpcServices’ özelliğine bu sefer ‘Client’ niteliği verilmiştir.
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması
Velhasıl, ilgili client uygulamasında da gerekli servis ve mesaj türlerini generate edebilmemiz için uygulamanın derlenmesi gerekmektedir. Derleme neticesinde
'obj' -> 'Debug' -> 'net5.0'
dizininde yandaki gibi ilgili sınıfların oluşturulduğunu görebilmekteyiz.

Artık tek yapılması gereken client’tan server’a istekte bulunmak ve response’u elde etmek. Bunun için console uygulamasının ‘Program.cs’ dosyasında aşağıdaki çalışmanın yapılması yeterli olacaktır.

    class Program
    {
        static async Task Main(string[] args)
        {
            var channel = GrpcChannel.ForAddress("https://localhost:5001");
            var greetClient = new Greeter.GreeterClient(channel);
            HelloReply response = await greetClient.SayHelloAsync(new HelloRequest { Name = "Gençay" });
            Console.WriteLine($"Gelen Cevap : {response.Message}");
        }
    }

Yukarıdaki kod bloğunu incelerseniz eğer; gRPC server’a istek gönderebilmek için ilgili server’ın adresini dinleyen bir channel oluşturulmakta ve bu channel üzerinden client üretilip, ayağa kaldırılmaktadır. Ardından client üzerinden server’da ki metot(SayHello) istediği ‘HelloRequest’ nesnesiyle birlikte tetiklenmekte ve neticede ‘HelloReply’ response’u elde edilmektedir.

Test Edelim

Uygulamayı test edebilmek için client ve server uygulamalarını derleyip, ayağa kaldıralım ve aşağıdaki ekran görüntüsünde olduğu gibi sonucu gözlemleyelim:
gRPC'de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması
Evet… Görüldüğü üzere client tarafından yapılan istek server tarafından karşılandı ve beklenen sonuç elde edilmiş oldu 🙂 Tabi ki tüm bu süreç Http/2 protokolü üzerinden yaklaşık 2.5 kat daha hızlı bir şekilde ceyran etti 🙂

Harika değil mi…

Nihai olarak;
Bu içeriğimizde, bir gRPC operasyonunun nasıl gerçekleştirildiğini hem server hem de client tabanlı olmak üzere tüm incelikleriyle ele almış ve incelemiş bulunmaktayız. Sonraki içeriklerimizde ise gRPC’de veri iletim yöntemlerini özelleştirilmiş proto dosyaları üzerinden tek tek ele alıyor olacağız.

O halde en kısa zamanda görüşmek üzere diyelim 🙂

İlgilenenlerin faydalanması dileğiyle…
İyi çalışmalar…

Not : Örnek çalışma projelerini indirebilmek için aşağıdaki linklere tıklayınız.
gRPCClientExample
gRPCExample

Bunlar da hoşunuza gidebilir...

5 Cevaplar

  1. Özgür dedi ki:

    Merhabalar Gencay Hocam,

    Öncelikle ilgili paylaşımınız ve emeğiniz adına teşekkürlerimi bir borç bilirim.

    Grpc ile ilgili ufak bir sorun yaşamaktayım. Sorunum şudur;
    MSB6006 : “root\windows_x86\protoc.exe” exited with code -1073741819
    Bütün paketler doğru bir şekilde yükleniyor, ancak proje build edilirken böyle bir hata ile karşılaşıyorum. Farklı cihazlardan da denedim ancak aynı hata devam ediyor. Araştırmalarımla da sorunu henüz çözümleyemedim. Böyle bir hata ile karşılaştınız mı daha öncesinde?

    Saygılarımla…

    • Gençay dedi ki:

      Merhaba,

      İşletim sisteminde kullanılan oturumun adında Türkçe karakter var mı?

      • Özgür dedi ki:

        Merhabalar Gencay Hocam,

        Hata tahmin ettiğiniz üzere işletim sisteminin kullanıcı adı ile ilgili (Türkçe karakterden dolayı protoc.exe doğru çalıştırılamıyor). Bunu düzelttiğimde başarılı bir şekilde build işlemini sağlayabildim. Umarım bu sorunla karşılaşan arkadaşlara yardımcı olur.

        İlginiz ve yardımlarınız adına teşekkür ederim. 🙂

        Saygılarımla…

  1. 04 Ocak 2021

    […] önceki gRPC’de Client ve Server Uygulamaları, Proto Dosyası ve Servislerin Oluşturulması başlıklı makalemizde gRPC üzerine pratikte uzun ve detaylı bir incelemede bulunmuştuk. Bu […]

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir