{"id":3837,"date":"2021-09-27T10:30:15","date_gmt":"2021-09-27T08:30:15","guid":{"rendered":"https:\/\/gokhan-gokalp.com\/?p=3837"},"modified":"2021-09-27T10:30:15","modified_gmt":"2021-09-27T08:30:15","slug":"high-performance-stream-based-communication-between-services-with-net-5-and-grpc","status":"publish","type":"post","link":"https:\/\/gokhan-gokalp.com\/tr\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/","title":{"rendered":".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim"},"content":{"rendered":"<p>G\u00fcn\u00fcm\u00fcz teknoloji \u00e7a\u011f\u0131n\u0131n ihtiya\u00e7lar\u0131 nedeniyle geli\u015ftirdi\u011fimiz bir \u00e7ok uygulamalar\u0131m\u0131z\u0131, <strong>microservice<\/strong> mimarisi \u00e7at\u0131s\u0131 alt\u0131nda <strong>distributed<\/strong> olarak geli\u015ftirmeye \u00e7al\u0131\u015f\u0131yoruz. Ayr\u0131ca distributed servisler aras\u0131ndaki ileti\u015fimi ise bir \u00e7ok noktada <em><strong>REST<\/strong><\/em>\u00a0 (HTTP JSON) yakla\u015f\u0131m\u0131yla ger\u00e7ekle\u015ftirmeye \u00e7al\u0131\u015f\u0131yoruz.<\/p>\n<p>Bu makale kapsam\u0131nda ise <em><strong>gRPC<\/strong><\/em> kullanarak servisler aras\u0131nda y\u00fcksek performansl\u0131, stream tabanl\u0131 ileti\u015fimi nas\u0131l ger\u00e7ekle\u015ftirebiliriz ve <em><strong>gRPC<\/strong><\/em> kullanarak ne gibi faydalar elde edebiliriz konusuna de\u011finmeye \u00e7al\u0131\u015faca\u011f\u0131m.<\/p>\n<h2>Neden?<\/h2>\n<p><a href=\"\/wp-content\/uploads\/2021\/09\/distributed-services.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-3873 lazyload\" data-src=\"\/wp-content\/uploads\/2021\/09\/distributed-services.jpg\" alt=\"\" width=\"920\" height=\"613\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/distributed-services.jpg 920w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/distributed-services-300x200.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/distributed-services-768x512.jpg 768w\" data-sizes=\"(max-width: 920px) 100vw, 920px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 920px; --smush-placeholder-aspect-ratio: 920\/613;\" \/><\/a><\/p>\n<p>Bildi\u011fimiz gibi bazen baz\u0131 senaryolar vard\u0131r milisaniyelerin de \u00f6neminin oldu\u011fu. Bu gibi durumlarda performans\u0131 artt\u0131rabilmek i\u00e7in genelde kodsal a\u00e7\u0131dan refactoring&#8217;ler yapmaya veya implementasyon y\u00f6ntemlerini de\u011fi\u015ftirmeye \u00e7al\u0131\u015f\u0131r\u0131z (eminim bir developer olarak sizde kar\u015f\u0131la\u015fm\u0131\u015fs\u0131n\u0131zd\u0131r). \u0130\u015fte bu noktada <em><strong>gRPC<\/strong><\/em> de senaryolara g\u00f6re performans\u0131 artt\u0131rabilmek i\u00e7in yararlanabilece\u011fimiz harika bir implementasyon\/ileti\u015fim yakla\u015f\u0131m\u0131d\u0131r.<\/p>\n<p>\u00d6zellikle servisler aras\u0131 ileti\u015fim s\u0131ras\u0131nda aktar\u0131lacak olan payload&#8217;un boyutu b\u00fcy\u00fckse veya streaming gibi yakla\u015f\u0131mlardan yararlanmak istiyorsak, <em><strong>gRPC<\/strong><\/em> bu noktada harika bir ileti\u015fim se\u00e7imi oluyor. \u00c7\u00fcnk\u00fc <em><strong>gRPC<\/strong>,<\/em>\u00a0<em>HTTP\/2<\/em> protokol\u00fc \u00fczerinden protocol buffer(<em>Protobuf<\/em>) kullanarak <strong>binary serialization<\/strong> yapt\u0131\u011f\u0131 ve <strong>binary data<\/strong> transfer etti\u011fi i\u00e7in servisler aras\u0131 ileti\u015fimde olduk\u00e7a y\u00fcksek bir performans sa\u011flayabilmektedir.<\/p>\n<p>Ayr\u0131ca <em>.NET 5<\/em> ile birlikte <em>HTTP\/2 <\/em>ve<em> Kestrel<\/em> \u00f6zelinde ger\u00e7ekle\u015ftirilen allocation&#8217;lar\u0131n azalt\u0131lmas\u0131 ve concurrency&#8217;nin iyile\u015ftirilmesi gibi optimizasyonlar ile, <em>gRPC<\/em> daha da iyi bir noktaya gelmi\u015ftir.<\/p>\n<p><em><strong>REST<\/strong> <\/em>yakla\u015f\u0131m\u0131nda ise bildi\u011fimiz gibi servisler aras\u0131nda data&#8217;y\u0131 <em>JSON<\/em> veya <em>XML<\/em> olarak transfer etti\u011fimiz i\u00e7in, payload boyutunun binary data&#8217;ya g\u00f6re daha b\u00fcy\u00fck olmas\u0131, serialization s\u00fcresi gibi \u00e7e\u015fitli sebeplerden dolay\u0131 servisler aras\u0131 ileti\u015fim senaryolara g\u00f6re daha yava\u015f olabilmektedir.<\/p>\n<h2>\u00d6rne\u011fin<\/h2>\n<p>\u00d6rne\u011fin bir e-ticaret firmas\u0131nda \u00e7al\u0131\u015ft\u0131\u011f\u0131m\u0131z\u0131 ve bir tedarik\u00e7i portal&#8217;i geli\u015ftirdi\u011fimizi varsayal\u0131m. Bizden ise tedarik\u00e7ilerin \u00fcr\u00fcnlerini bizim sistemimize toplu ve h\u0131zl\u0131 bir \u015fekilde <em>CSV\/XML<\/em> gibi bir formatta aktarabilmeleri istenmektedir.<\/p>\n<p>Normal \u015fartlarda tedarik\u00e7ilerin \u00fcr\u00fcnlerini toplu bir \u015fekilde upload edebilecekleri bir endpoint geli\u015ftiririz. Bu endpoint i\u00e7erisinde ise <em>CSV\/XML<\/em> dosyas\u0131n\u0131 parse ettikten sonra \u00fcr\u00fcnlerin sistem i\u00e7erisine dahil olabilme s\u00fcre\u00e7lerini ba\u015flatabilmek i\u00e7in ilgili internal <em>API<\/em>&#8216;lara\/Queue&#8217;lara istekler g\u00f6ndeririz. As\u0131l challenge ise i\u015fte bu noktada ba\u015fl\u0131yor.<\/p>\n<p>\u0130lgili internal <em>API&#8217;<\/em>lara istekler g\u00f6nderirken optimal olabilmesi a\u00e7\u0131s\u0131ndan duruma g\u00f6re ya chunk&#8217;lar halinde yada tek tek g\u00f6ndermeye \u00e7al\u0131\u015f\u0131r\u0131z. Bu i\u015flemleri bir <em>HTTP JSON API<\/em>&#8216;\u0131 \u00fczerinden sorunsuz bir \u015fekilde elbette ger\u00e7ekle\u015ftirebiliriz. Fakat bu noktada baz\u0131 dezavantajlar ile de kar\u015f\u0131la\u015fabiliriz. \u00d6rne\u011fin aktar\u0131lacak olan payload&#8217;lar\u0131n boyutu \u00fcr\u00fcn bilgilerinden dolay\u0131 b\u00fcy\u00fck olaca\u011f\u0131 i\u00e7in, bu noktada serialization veya network kaynakl\u0131 performans sorunlar\u0131yla kar\u015f\u0131la\u015fabiliriz. Ayr\u0131ca aktar\u0131lacak \u00e7ok fazla data da mevcutsa, buda daha fazla bir zaman kayb\u0131 olarak bize geriye d\u00f6nmektedir.<\/p>\n<p>\u0130\u015fte bu noktada <em>gRPC<\/em>&#8216;nin <strong>binary serialization<\/strong>,<em><strong> HTTP\/2<\/strong> <\/em>ve <strong>streaming<\/strong> gibi \u00f6zelliklerinden yararlanarak, bu internal ileti\u015fim s\u00fcrecini daha efektif, performansl\u0131 ve asynchronous bir hale getirebilmek m\u00fcmk\u00fcn olabilmektedir.<\/p>\n<h2>gRPC ile Client Streaming<\/h2>\n<p>Client streaming,<em> gRPC<\/em>&#8216;nin 4 farkl\u0131 yakla\u015f\u0131m tipinden birisidir. Di\u011ferleri ise &#8220;Unary&#8221;, &#8220;Server streaming&#8221; ve &#8220;Bidirectional streaming&#8221; dir.<\/p>\n<p>Client streaming \u00f6zellikle server&#8217;a <strong>s\u00fcrekli<\/strong> bir dizi data g\u00f6nderilmesi gereken durumlarda olduk\u00e7a faydal\u0131 ve performansl\u0131 bir yakla\u015f\u0131md\u0131r. Ayr\u0131ca streaming yakla\u015f\u0131m\u0131 \u00f6zellikle d\u00fc\u015f\u00fck bir gecikme s\u00fcresi ile y\u00fcksek bir aktar\u0131m h\u0131z\u0131 s\u00f6z konusu oldu\u011funda g\u00fczel bir se\u00e7im olmaktad\u0131r.<\/p>\n<p>\u00d6rnek senaryomuzda ise tedarik\u00e7i portal&#8217;i i\u00e7in birden \u00e7ok \u00fcr\u00fcn\u00fc bir noktadan bir ba\u015fka noktaya stream ederek g\u00f6nderece\u011fimiz i\u00e7in, <strong>client streaming<\/strong> yakla\u015f\u0131m\u0131n\u0131 implemente edece\u011fiz.<\/p>\n<p>Konuyu daha iyi anlayabilmek i\u00e7in \u015fimdi bir \u00f6rnek ger\u00e7ekle\u015ftirelim.<\/p>\n<p>Implementasyona ba\u015flamadan \u00f6nce a\u015fa\u011f\u0131daki gibi bir <em>CSV<\/em> dosyas\u0131na sahip oldu\u011fumuzu varsayal\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2021\/09\/sup_products_csv.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-3846 lazyload\" data-src=\"\/wp-content\/uploads\/2021\/09\/sup_products_csv.jpg\" alt=\"\" width=\"491\" height=\"140\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/sup_products_csv.jpg 491w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/sup_products_csv-300x86.jpg 300w\" data-sizes=\"(max-width: 491px) 100vw, 491px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 491px; --smush-placeholder-aspect-ratio: 491\/140;\" \/><\/a><\/p>\n<h3>Server Implementasyonu ile ba\u015flayal\u0131m<\/h3>\n<p>Geli\u015ftirmeye ise ilk olarak server k\u0131sm\u0131ndan ba\u015flayal\u0131m. Yani \u00fcr\u00fcnleri y\u00f6netecek oldu\u011fumuz as\u0131l \u00fcr\u00fcn servisi. Bunun i\u00e7in &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221; ad\u0131nda bir <em>.NET 5 gRPC<\/em> servisi olu\u015ftural\u0131m.<\/p>\n<pre>dotnet new grpc -n MyTodoStore.Product.GRPC<\/pre>\n<p><em>gRPC<\/em>\u00a0contract-first bir framework oldu\u011fu i\u00e7in ilk olarak <em>Protobuf<\/em> kullanarak contract&#8217;lar\u0131\u00a0tan\u0131mlamam\u0131z gerekmektedir.<\/p>\n<p><em>Protobuf&#8217;<\/em>\u0131 ise herhangi bir programlama diline ba\u011f\u0131ml\u0131 olmadan servisler aras\u0131 ileti\u015fimde kullanabilece\u011fimiz bir contract\/interface olarak d\u00fc\u015f\u00fcnebiliriz. Ayr\u0131ca olu\u015fturulacak olan contract&#8217;lar ilgili framework&#8217;ler taraf\u0131ndan kullan\u0131larak, servisler aras\u0131 ileti\u015fim i\u00e7in gerekli olan altyap\u0131n\u0131n otomatik olarak olu\u015fturulabilmesini de sa\u011flamaktad\u0131r.<\/p>\n<p>\u015eimdi &#8220;<em>Protos<\/em>&#8221; klas\u00f6r\u00fc alt\u0131nda &#8220;<em>product.proto<\/em>&#8221; dosyas\u0131n\u0131 a\u015fa\u011f\u0131daki gibi olu\u015ftural\u0131m.<\/p>\n<pre>syntax = \"proto3\";\r\n\r\noption csharp_namespace = \"MyTodoStore.Product.GRPC\";\r\n\r\npackage mytodostore_product_grpc;\r\n\r\nservice ProductGRPCService {\r\n  rpc ImportProductsStream(stream ImportProductRequest) returns (ImportProductResponse);\r\n}\r\n\r\nmessage ImportProductRequest {\r\n  int32 supplier_id = 1;\r\n  string sku = 2;\r\n  string name = 3;\r\n  string description = 4;\r\n  string brand = 5;\r\n}\r\n\r\nmessage ImportProductResponse {\r\n  int32 count = 1;\r\n}\r\n<\/pre>\n<p>Bu proto dosyas\u0131 i\u00e7erisinde bizim i\u00e7in \u00f6nemli olan nokta, <em>RPC<\/em>\u00a0method tan\u0131mlamalar\u0131n\u0131 yapt\u0131\u011f\u0131m\u0131z &#8220;<em>service<\/em>&#8221; k\u0131sm\u0131d\u0131r. Bu k\u0131s\u0131mda \u00fcr\u00fcnlerin sistem i\u00e7erisine bir stream olarak aktar\u0131labilmesinden sorumlu olacak olan &#8220;<em>ImportProductsStream<\/em>&#8221; adl\u0131 bir <em>RPC<\/em> method&#8217;u tan\u0131mlad\u0131k. Bu method stream olarak &#8220;<em>ImportProductRequest<\/em>&#8221; message&#8217;\u0131 kabul edecek ve i\u015flem tamamland\u0131\u011f\u0131nda ise geriye toplam aktar\u0131lan \u00fcr\u00fcn bilgisini i\u00e7eren bir &#8220;<em>ImportProductResponse<\/em>&#8221; message&#8217;\u0131 d\u00f6necek.<\/p>\n<p>Message structure&#8217;lar\u0131 i\u00e7erisindeki field&#8217;lara atanan unique rakamlar ise, serialize edilen binary data i\u00e7erisinde field&#8217;lar\u0131n tan\u0131mlanabilmesi i\u00e7in kullan\u0131lmaktad\u0131r. B\u00f6ylelikle message i\u00e7erisine yeni bir field eklendi\u011finde, o g\u00fcncellemeye sahip olmayan uygulaman\u0131n parser&#8217;\u0131 deserialization i\u015flemi s\u0131ras\u0131nda herhangi bir sorun \u00e7\u0131kartmadan ilgili field&#8217;\u0131 es ge\u00e7erek i\u015flemini ger\u00e7ekle\u015ftirebilmekte ve uyumsuzluk problemi \u00e7\u0131kartmamaktad\u0131r.<\/p>\n<blockquote><p><em><strong>NOT<\/strong><\/em>: Proto dosyas\u0131 olu\u015fturma hakk\u0131nda daha detayl\u0131 bilgiye ise <em><a href=\"https:\/\/developers.google.com\/protocol-buffers\/docs\/proto3\" target=\"_blank\" rel=\"noopener\">buradaki<\/a><\/em> kaynaktan ula\u015fabilirsiniz.<\/p><\/blockquote>\n<p>&#8220;<em>product.proto<\/em>&#8221; dosyas\u0131n\u0131 olu\u015fturduktan sonra code generation i\u015fleminin ger\u00e7ekle\u015febilmesi i\u00e7in, proje dosyas\u0131 i\u00e7erisinde de a\u015fa\u011f\u0131daki gibi onu tan\u0131mlamam\u0131z gerekmektedir.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2021\/09\/proto-csproj.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-3851 lazyload\" data-src=\"\/wp-content\/uploads\/2021\/09\/proto-csproj.jpg\" alt=\"\" width=\"784\" height=\"244\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/proto-csproj.jpg 784w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/proto-csproj-300x93.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/proto-csproj-768x239.jpg 768w\" data-sizes=\"(max-width: 784px) 100vw, 784px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 784px; --smush-placeholder-aspect-ratio: 784\/244;\" \/><\/a><\/p>\n<p>B\u00f6ylece &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221; projesini build etti\u011fimizde, compiler olu\u015fturdu\u011fumuz proto dosyas\u0131n\u0131 kullanarak gerekli code generation i\u015flemini server i\u00e7in ger\u00e7ekle\u015ftirecektir. K\u0131sacas\u0131 tan\u0131mlama i\u015flemini ger\u00e7ekle\u015ftirdikten sonra projeyi build etmeyi unutmayal\u0131m.<\/p>\n<p>\u015eimdi ise &#8220;<em>Services<\/em>&#8221; klas\u00f6r\u00fc alt\u0131nda &#8220;<em>ProductService<\/em>&#8221; isminde a\u015fa\u011f\u0131daki gibi bir class olu\u015ftural\u0131m ve servis implementasyonunu ger\u00e7ekle\u015ftirelim.<\/p>\n<pre>using System;\r\nusing System.Threading.Tasks;\r\nusing Grpc.Core;\r\n\r\nnamespace MyTodoStore.Product.GRPC\r\n{\r\n    public class ProductService : ProductGRPCService.ProductGRPCServiceBase\r\n    {\r\n        public override async Task&lt;ImportProductResponse&gt; ImportProductsStream(IAsyncStreamReader&lt;ImportProductRequest&gt; requestStream, ServerCallContext context)\r\n        {\r\n            var importResponse = new ImportProductResponse();\r\n\r\n            await foreach (var importProductItem in requestStream.ReadAllAsync())\r\n            {\r\n                \/\/ product import operations...\r\n\r\n                importResponse.Count += 1;\r\n                Console.WriteLine($\"1 product has been imported. SKU: {importProductItem.Sku} Brand: {importProductItem.Brand}\");\r\n            }\r\n\r\n            Console.WriteLine(\"Import products stream has been ended.\");\r\n\r\n            return importResponse;\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>G\u00f6rd\u00fc\u011f\u00fcm\u00fcz gibi bu class&#8217;\u0131, compiler taraf\u0131ndan olu\u015fturulan &#8220;<em>ProductGRPCServiceBase<\/em>&#8221; abstract class&#8217;\u0131ndan t\u00fcrettik. Ard\u0131ndan &#8220;<em>ImportProductsStream<\/em>&#8221; adl\u0131 <em>RPC<\/em> method&#8217;unu burada override ederek, i\u00e7erisinde stream&#8217;i consume etti\u011fimiz basit bir business kodu ile implemente ettik.<\/p>\n<p>Bu business kodundaki amac\u0131m\u0131z ise \u00fcr\u00fcnleri server&#8217;a stream ederken bu i\u015flemi <strong>async<\/strong> bir \u015fekilde ba\u015flatabildi\u011fimizi, bir ba\u015fka de\u011fi\u015fle server&#8217;\u0131n t\u00fcm \u00fcr\u00fcn stream ak\u0131\u015f\u0131n\u0131n tamamlanmas\u0131n\u0131 beklemeden async bir \u015fekilde \u00e7al\u0131\u015fmaya ba\u015flayabildi\u011fini g\u00f6sterebilmek. Bunun i\u00e7in sisteme aktar\u0131lan \u00fcr\u00fcn say\u0131s\u0131n\u0131 &#8220;foreach&#8221; loop&#8217;u i\u00e7erisinde artt\u0131raca\u011f\u0131z ve geriye toplam ka\u00e7 adet \u00fcr\u00fcn aktar\u0131ld\u0131\u011f\u0131 bilgisini i\u00e7eren &#8220;<em>importResponse<\/em>&#8221; messag\u0131&#8217;\u0131n\u0131 d\u00f6nece\u011fiz.<\/p>\n<p>Servis implementasyonunu tamamlad\u0131ktan sonra &#8220;<em>Startup<\/em>&#8221; dosyas\u0131 i\u00e7erisinde a\u015fa\u011f\u0131daki gibi endpoint mapping i\u015flemini de ger\u00e7ekle\u015ftirmemiz gerekmektedir.<\/p>\n<pre>public void Configure(IApplicationBuilder app, IWebHostEnvironment env)\r\n{\r\n    if (env.IsDevelopment())\r\n    {\r\n        app.UseDeveloperExceptionPage();\r\n    }\r\n\r\n    app.UseRouting();\r\n\r\n    app.UseEndpoints(endpoints =&gt;\r\n    {\r\n        endpoints.MapGrpcService&lt;ProductService&gt;();\r\n\r\n        endpoints.MapGet(\"\/\", async context =&gt;\r\n        {\r\n            await context.Response.WriteAsync(\"Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https:\/\/go.microsoft.com\/fwlink\/?linkid=2086909\");\r\n        });\r\n    });\r\n}\r\n<\/pre>\n<p>Neredeyse haz\u0131r\u0131z.<\/p>\n<p>E\u011fer sizde benim gibi <em>macOS<\/em> kullan\u0131yorsan\u0131z, a\u015fa\u011f\u0131daki gibi <em>Kestrel&#8217;i <\/em>configure\u00a0etmeniz gerekmektedir. \u00c7\u00fcnk\u00fc <em>Kestrel<\/em>, <em>macOS<\/em> i\u00e7erisinde <em>HTTP\/2<\/em> ile <em>TLS<\/em>&#8216;i desteklememektedir.<\/p>\n<pre>using Microsoft.AspNetCore.Hosting;\r\nusing Microsoft.AspNetCore.Server.Kestrel.Core;\r\nusing Microsoft.Extensions.Hosting;\r\n\r\nnamespace MyTodoStore.Product.GRPC\r\n{\r\n    public class Program\r\n    {\r\n        public static void Main(string[] args)\r\n        {\r\n            CreateHostBuilder(args).Build().Run();\r\n        }\r\n\r\n        public static IHostBuilder CreateHostBuilder(string[] args) =&gt;\r\n            Host.CreateDefaultBuilder(args)\r\n                .ConfigureWebHostDefaults(webBuilder =&gt;\r\n                {\r\n                    webBuilder.ConfigureKestrel(options =&gt;\r\n                    {\r\n                        options.ListenLocalhost(5000, o =&gt; o.Protocols =\r\n                            HttpProtocols.Http2);\r\n                    });\r\n\r\n                    webBuilder.UseStartup&lt;Startup&gt;();\r\n                });\r\n    }\r\n}\r\n<\/pre>\n<p>Art\u0131k &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221; servisi haz\u0131r durumda.<\/p>\n<h3>Client Implementasyonu<\/h3>\n<p>\u015eimdi ise tedarik\u00e7i \u00fcr\u00fcn i\u015flemleri i\u00e7in kullanaca\u011f\u0131m\u0131z bir <em>RESTful<\/em>\u00a0<em>API<\/em> geli\u015ftirelim. Temel olarak bu <em>API&#8217;<\/em>da i\u00e7erisinde ise <em>CSV<\/em> dosyas\u0131n\u0131n upload i\u015flemini implemente edece\u011fiz.<\/p>\n<p>Bunun i\u00e7in &#8220;<em>MyTodoStore.SupplierProduct.API<\/em>&#8221; ad\u0131nda bir <em>.NET 5 Web API<\/em> projesi olu\u015ftural\u0131m.<\/p>\n<pre>dotnet new webapi -n MyTodoStore.SupplierProduct.API<\/pre>\n<p>Ard\u0131ndan <em>CSV<\/em> dosyas\u0131n\u0131 kolayca parse edebilmemiz ve <em>gRPC<\/em> client implementasyonunu ger\u00e7ekle\u015ftirebilmemiz i\u00e7in a\u015fa\u011f\u0131daki paket&#8217;leri <em>NuGet<\/em> \u00fczerinden projeye dahil edelim.<\/p>\n<pre>dotnet add package CsvHelper\r\ndotnet add package Grpc.Net.Client\r\ndotnet add package Grpc.Net.ClientFactory<\/pre>\n<p>Paketleri projeye dahil ettikten sonra ise olu\u015fturmu\u015f oldu\u011fumuz &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221;\u00a0servisinin &#8220;<em>product.proto<\/em>&#8221; dosyas\u0131n\u0131, bu proje alt\u0131nda &#8220;<em>Protos<\/em>&#8221; klas\u00f6r\u00fc olu\u015fturarak i\u00e7erisine kopyalayal\u0131m. Daha sonra yeni kopyalad\u0131\u011f\u0131m\u0131z proto dosyas\u0131 i\u00e7erisindeki &#8220;<em>csharp_namespace<\/em>&#8221; alan\u0131n\u0131 ise, yeni olu\u015fturmu\u015f oldu\u011fumuz proje namespace&#8217;i ile g\u00fcncelleyelim.<\/p>\n<pre>option csharp_namespace = \"MyTodoStore.SupplierProduct.API\";<\/pre>\n<p>Ard\u0131ndan bu proje dosyas\u0131 i\u00e7erisinde de &#8220;<em>product.proto<\/em>&#8221; dosyas\u0131n\u0131 a\u015fa\u011f\u0131daki gibi tan\u0131mlamam\u0131z gerekmektedir.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2021\/09\/client-proto.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-3852 lazyload\" data-src=\"\/wp-content\/uploads\/2021\/09\/client-proto.jpg\" alt=\"\" width=\"720\" height=\"72\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/client-proto.jpg 720w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/client-proto-300x30.jpg 300w\" data-sizes=\"(max-width: 720px) 100vw, 720px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 720px; --smush-placeholder-aspect-ratio: 720\/72;\" \/><\/a><\/p>\n<p>Proto dosyas\u0131n\u0131 bu projede tan\u0131mlarken buradaki farkl\u0131 olan nokta ise, &#8220;<em>GrpcServices<\/em>&#8221; attribute de\u011ferinin &#8220;<em>Client<\/em>&#8221; olmas\u0131d\u0131r. B\u00f6ylece compiler, <strong>server<\/strong> taraf\u0131na ba\u011flanabilmemiz i\u00e7in gerekli olan C# kodunu bu sefer client i\u00e7in olu\u015fturacakt\u0131r. Bu i\u015flemin ard\u0131ndan ise daha \u00f6nce de yapt\u0131\u011f\u0131m\u0131z gibi projeyi build etmeyi unutmayal\u0131m.<\/p>\n<p>\u015eimdi &#8220;<em>Models<\/em>&#8221; isminde bir klas\u00f6r olu\u015fturarak i\u00e7erisinde <em>CSV<\/em> dosyas\u0131n\u0131 temsil edecek olan modeli a\u015fa\u011f\u0131daki gibi tan\u0131mlayal\u0131m.<\/p>\n<pre>namespace MyTodoStore.SupplierProduct.API.Models\r\n{\r\n    public class SupplierProductModel\r\n    {\r\n        public int SupplierID { get; set; }\r\n        public string SKU { get; set; }\r\n        public string Name { get; set; }\r\n        public string Description { get; set; }\r\n        public string Brand { get; set; }\r\n    }\r\n}\r\n<\/pre>\n<p>Ard\u0131ndan servis implementasyonunu ger\u00e7ekle\u015ftirece\u011fimiz &#8220;<em>Services<\/em>&#8221; klas\u00f6r\u00fcn\u00fc olu\u015ftural\u0131m. \u0130\u00e7erisinde ise &#8220;<em>SupplierProductService&#8221;\u00a0<\/em>ad\u0131nda bir servisi, a\u015fa\u011f\u0131daki gibi implemente edelim.<\/p>\n<pre>using System.Threading.Tasks;\r\nusing Microsoft.AspNetCore.Http;\r\n\r\nnamespace MyTodoStore.SupplierProduct.API.Services\r\n{\r\n    public interface ISupplierProductService\r\n    {\r\n        Task&lt;int&gt; ImportProductsAsync(IFormFile formFile);\r\n    }\r\n}\r\n<\/pre>\n<pre>using System.Collections.Generic;\r\nusing System.Globalization;\r\nusing System.IO;\r\nusing System.Threading.Tasks;\r\nusing CsvHelper;\r\nusing CsvHelper.Configuration;\r\nusing Microsoft.AspNetCore.Http;\r\nusing MyTodoStore.SupplierProduct.API.Models;\r\n\r\nnamespace MyTodoStore.SupplierProduct.API.Services\r\n{\r\n    public class SupplierProductService : ISupplierProductService\r\n    {\r\n        private readonly ProductGRPCService.ProductGRPCServiceClient _productGRPCServiceClient;\r\n\r\n        public SupplierProductService(ProductGRPCService.ProductGRPCServiceClient productGRPCServiceClient)\r\n        {\r\n            _productGRPCServiceClient = productGRPCServiceClient;\r\n        }\r\n\r\n        public async Task&lt;int&gt; ImportProductsAsync(IFormFile formFile)\r\n        {\r\n            var config = new CsvConfiguration(CultureInfo.InvariantCulture)\r\n            {\r\n                Delimiter = \";\"\r\n            };\r\n\r\n            using var importProductStream = _productGRPCServiceClient.ImportProductsStream();\r\n\r\n            using (var reader = new StreamReader(formFile.OpenReadStream()))\r\n            using (var csv = new CsvReader(reader, config))\r\n            {\r\n                IAsyncEnumerable&lt;SupplierProductModel&gt; products = csv.GetRecordsAsync&lt;SupplierProductModel&gt;();\r\n\r\n                await foreach (SupplierProductModel product in products)\r\n                {\r\n                    ImportProductRequest importProductRequest = new()\r\n                    {\r\n                        SupplierId = product.SupplierID,\r\n                        Sku = product.SKU,\r\n                        Name = product.Name,\r\n                        Description = product.Description,\r\n                        Brand = product.Brand\r\n                    };\r\n\r\n                    await importProductStream.RequestStream.WriteAsync(importProductRequest);\r\n                }\r\n            }\r\n            await importProductStream.RequestStream.CompleteAsync();\r\n\r\n            ImportProductResponse response = await importProductStream;\r\n\r\n            return response.Count;\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Burada basit olarak &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221; servisine ba\u011flanabilmek i\u00e7in compiler taraf\u0131ndan olu\u015fturulan &#8220;<em>ProductGRPCServiceClient<\/em>&#8221; client&#8217;\u0131n\u0131 inject ettik.<\/p>\n<p>Ard\u0131ndan &#8220;<em>ImportProductsAsync<\/em>&#8221; method&#8217;u i\u00e7erisinde <em>CsvHelper<\/em> paketini kullanarak <em>CSV <\/em>dosyas\u0131n\u0131n\u00a0parse i\u015flemini ger\u00e7ekle\u015ftirdik ve her bir \u00fcr\u00fcn\u00fc &#8220;<em>ProductGRPCServiceClient<\/em>&#8221; client&#8217;\u0131 \u00fczerinden tek tek stream ederek server taraf\u0131na g\u00f6nderdik.<\/p>\n<p>Server&#8217;a stream i\u015fleminin tamamland\u0131\u011f\u0131n\u0131 bildirebilmek i\u00e7in ise, a\u015fa\u011f\u0131daki gibi stream&#8217;in &#8220;<em>CompleteAsync<\/em>&#8221; method&#8217;unu \u00e7a\u011f\u0131rd\u0131k.<\/p>\n<pre>await importProductStream.RequestStream.CompleteAsync();<\/pre>\n<p>B\u00f6ylece streaming i\u015flemi tamamlanm\u0131\u015f olacak ve server ilgili channel&#8217;\u0131 kapatarak geriye ne kadar \u00fcr\u00fcn import edildi\u011fi bilgisini bize response olarak d\u00f6necektir.<\/p>\n<p>\u015eimdi &#8220;<em>Product<\/em>&#8221; ad\u0131nda bir controller olu\u015ftural\u0131m ve i\u00e7erisinde <em>CSV<\/em>&#8216;yi upload edebilece\u011fimiz endpoint&#8217;i implemente edelim.<\/p>\n<pre>using System.Threading.Tasks;\r\nusing Microsoft.AspNetCore.Http;\r\nusing Microsoft.AspNetCore.Mvc;\r\nusing MyTodoStore.SupplierProduct.API.Services;\r\n\r\nnamespace MyTodoStore.SupplierProduct.API.Controllers\r\n{\r\n    [ApiController]\r\n    [Route(\"products\")]\r\n    public class ProductController : ControllerBase\r\n    {\r\n        private readonly ISupplierProductService _supplierProductService;\r\n\r\n        public ProductController(ISupplierProductService supplierProductService)\r\n        {\r\n            _supplierProductService = supplierProductService;\r\n        }\r\n\r\n        [HttpPost]\r\n        public async Task&lt;IActionResult&gt; UploadProducts(IFormFile formFile)\r\n        {\r\n            int importedProductCount = await _supplierProductService.ImportProductsAsync(formFile);\r\n\r\n            return Ok($\"{importedProductCount} products have been imported.\");\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>Ard\u0131ndan &#8220;<em>Startup<\/em>&#8221; dosyas\u0131 i\u00e7erisinde a\u015fa\u011f\u0131daki gibi gerekli servis injection i\u015flemini ve <em>gRPC<\/em> client&#8217;\u0131n\u0131n kay\u0131t i\u015flemini ger\u00e7ekle\u015ftirelim. <em>gRPC<\/em> client&#8217;\u0131n\u0131n kay\u0131t i\u015flemi i\u00e7in ise &#8220;<em>Grpc.Net.ClientFactory<\/em>&#8221; paketi ile gelen, &#8220;<em>AddGrpcClient<\/em>&#8221; method&#8217;unu kullanaca\u011f\u0131z.<\/p>\n<p>Bu paket sayesinde <em>gRPC<\/em> client&#8217;lar\u0131n\u0131 merkezi bir noktadan configure edebilmekteyiz. Ayr\u0131ca bu paket, performansl\u0131 bir ileti\u015fim sa\u011flayabilmemiz i\u00e7in channel&#8217;lar\u0131n tekrar kullan\u0131labilmesini otomatik olarak sa\u011flamaktad\u0131r. \u00c7\u00fcnk\u00fc yeni bir channel&#8217;\u0131n a\u00e7\u0131lmas\u0131 demek, hem client hem de server taraf\u0131nda bir network round-trip&#8217;inin yap\u0131lmas\u0131 demektir.<\/p>\n<pre>public void ConfigureServices(IServiceCollection services)\r\n{\r\n\r\n    services.AddControllers();\r\n    services.AddSwaggerGen(c =&gt;\r\n    {\r\n        c.SwaggerDoc(\"v1\", new OpenApiInfo { Title = \"MyTodoStore.SupplierProduct.API\", Version = \"v1\" });\r\n    });\r\n\r\n    services.AddScoped&lt;ISupplierProductService, SupplierProductService&gt;();\r\n\r\n    services.AddGrpcClient&lt;ProductGRPCService.ProductGRPCServiceClient&gt;(o =&gt;\r\n    {\r\n        o.Address = new Uri(\"http:\/\/localhost:5000\");\r\n    });\r\n}\r\n<\/pre>\n<p>Son olarak <em>API<\/em>&#8216;\u0131 farkl\u0131 bir port \u00fczerinden eri\u015fime a\u00e7mam\u0131z gerekmektedir. \u00c7\u00fcnk\u00fc default &#8220;<em>5000<\/em>&#8221; port&#8217;u, olu\u015fturmu\u015f oldu\u011fumuz <em>gRPC<\/em> servisi taraf\u0131ndan kullan\u0131lmaktad\u0131r. Bu <em>API<\/em>&#8216;\u0131 ise, &#8220;<em>5001<\/em>&#8221; portu \u00fczerinden a\u015fa\u011f\u0131daki gibi eri\u015fime a\u00e7al\u0131m.<\/p>\n<pre>using Microsoft.AspNetCore.Hosting;\r\nusing Microsoft.Extensions.Hosting;\r\n\r\nnamespace MyTodoStore.SupplierProduct.API\r\n{\r\n    public class Program\r\n    {\r\n        public static void Main(string[] args)\r\n        {\r\n            CreateHostBuilder(args).Build().Run();\r\n        }\r\n\r\n        public static IHostBuilder CreateHostBuilder(string[] args) =&gt;\r\n            Host.CreateDefaultBuilder(args)\r\n                .ConfigureWebHostDefaults(webBuilder =&gt;\r\n                {\r\n                    webBuilder.UseUrls(\"https:\/\/*:5001\");\r\n                    webBuilder.UseStartup&lt;Startup&gt;();\r\n                });\r\n    }\r\n}\r\n<\/pre>\n<p>\u015eimdi test etmeye haz\u0131r\u0131z.<\/p>\n<h3>Test Edelim<\/h3>\n<p>\u00d6ncelikle a\u015fa\u011f\u0131daki gibi her iki projeyi de \u00e7al\u0131\u015ft\u0131ral\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2021\/09\/run-projects-grpc.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-3855 lazyload\" data-src=\"\/wp-content\/uploads\/2021\/09\/run-projects-grpc.jpg\" alt=\"\" width=\"1652\" height=\"563\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/run-projects-grpc.jpg 1652w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/run-projects-grpc-300x102.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/run-projects-grpc-1024x349.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/run-projects-grpc-768x262.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/run-projects-grpc-1536x523.jpg 1536w\" data-sizes=\"(max-width: 1652px) 100vw, 1652px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1652px; --smush-placeholder-aspect-ratio: 1652\/563;\" \/><\/a><\/p>\n<p>Ard\u0131ndan &#8220;<em>https:\/\/localhost:5001\/swagger\/index.html<\/em>&#8221; endpoint&#8217;i \u00fczerinden &#8220;<em>MyTodoStore.SupplierProduct.API<\/em>&#8221; \u0131n\u0131n\u00a0ara y\u00fcz\u00fcne eri\u015felim ve <em>CSV<\/em> dosyas\u0131n\u0131 &#8220;\/<em>products<\/em>&#8221; endpoint&#8217;i \u00fczerinden upload edelim.<\/p>\n<p>Bu i\u015flemden beklentimiz ise, her bir \u00fcr\u00fcn\u00fcn &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221; servisine <strong>stream<\/strong> edilerek g\u00f6nderilmesi ve geriye ne kadar \u00fcr\u00fcn aktar\u0131ld\u0131\u011f\u0131 bilgisinin tek bir response \u00fczerinden al\u0131nmas\u0131d\u0131r.<\/p>\n<p>Upload i\u015flemi ger\u00e7ekle\u015ftikten sonra terminal \u00fczerinden &#8220;<em>MyTodoStore.Product.GRPC<\/em>&#8221; servisinin log&#8217;lar\u0131na bir g\u00f6z atal\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2021\/09\/product-import2.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-3856 lazyload\" data-src=\"\/wp-content\/uploads\/2021\/09\/product-import2.jpg\" alt=\"\" width=\"1654\" height=\"266\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/product-import2.jpg 1654w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/product-import2-300x48.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/product-import2-1024x165.jpg 1024w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/product-import2-768x124.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/product-import2-1536x247.jpg 1536w\" data-sizes=\"(max-width: 1654px) 100vw, 1654px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1654px; --smush-placeholder-aspect-ratio: 1654\/266;\" \/><\/a><\/p>\n<p>Yukar\u0131daki terminal ekran\u0131na bakt\u0131\u011f\u0131m\u0131zda, \u00fcr\u00fcnlerin sistem i\u00e7erisine aktar\u0131lma i\u015flemi s\u0131ras\u0131nda log mesajlar\u0131 yaz\u0131ld\u0131\u011f\u0131n\u0131 g\u00f6rebiliriz.<\/p>\n<pre>1 product has been imported. SKU: ABC Brand: Samsung\r\n1 product has been imported. SKU: CDE Brand: Samsung\r\n1 product has been imported. SKU: GDE Brand: Apple\r\nImport products stream has been ended.<\/pre>\n<p>\u00dcr\u00fcnlerin sistem i\u00e7erisine aktar\u0131lmas\u0131ndan sorumlu olan kod blo\u011funu ise hat\u0131rlayal\u0131m.<\/p>\n<pre>public override async Task&lt;ImportProductResponse&gt; ImportProductsStream(IAsyncStreamReader&lt;ImportProductRequest&gt; requestStream, ServerCallContext context)\r\n{\r\n    var importResponse = new ImportProductResponse();\r\n\r\n    await foreach (var importProductItem in requestStream.ReadAllAsync())\r\n    {\r\n        \/\/ product import operations...\r\n\r\n        importResponse.Count += 1;\r\n        Console.WriteLine($\"1 product has been imported. SKU: {importProductItem.Sku} Brand: {importProductItem.Brand}\");\r\n    }\r\n\r\n    Console.WriteLine(\"Import products stream has been ended.\");\r\n\r\n    return importResponse;\r\n}<\/pre>\n<p>G\u00f6rd\u00fc\u011f\u00fcm\u00fcz gibi log mesajlar\u0131 &#8220;<em>requestStream<\/em>&#8221; i &#8220;foreach&#8221; loop&#8217;u i\u00e7erisinde consume ederken yazd\u0131r\u0131lmaktad\u0131r. Gelen stream client taraf\u0131ndan sona erdirildi\u011finde ise terminal ekran\u0131ndan da g\u00f6rebilece\u011fimiz \u00fczere &#8220;<em>Import products stream has been ended.<\/em>&#8221; log mesaj\u0131 yazd\u0131r\u0131lmaktad\u0131r.<\/p>\n<p>K\u0131sacas\u0131 \u00fcr\u00fcnlerin server&#8217;a stream i\u015fleminin, client hala \u00fcr\u00fcnlerin \u00fczerinde \u00e7al\u0131\u015f\u0131yorken server taraf\u0131ndan async bir \u015fekilde ele al\u0131nd\u0131\u011f\u0131n\u0131 ve stream i\u015flemi tamamland\u0131\u011f\u0131nda geriye ne kadar \u00fcr\u00fcn aktar\u0131ld\u0131\u011f\u0131 bilgisini i\u00e7eren &#8220;<em>ImportProductResponse<\/em>&#8221; message&#8217;\u0131 d\u00f6n\u00fcld\u00fc\u011f\u00fcn\u00fc g\u00f6rebilmekteyiz.<\/p>\n<h3>Resiliency<\/h3>\n<p>Servisler aras\u0131 y\u00fcksek performansl\u0131 bir ileti\u015fim sa\u011flayabilmek her ne kadar \u00f6nemliyse, ge\u00e7ici hatalara kar\u015f\u0131 haz\u0131rl\u0131kl\u0131 olabilmekte bi o kadar \u00f6nemlidir. <em>gRPC<\/em> d\u00fcnyas\u0131nda da network kaynakl\u0131 hatalara veya ilgili servislerin ge\u00e7ici bir s\u00fcre kullan\u0131lamaz olmas\u0131 gibi durumlara kar\u015f\u0131 haz\u0131rl\u0131kl\u0131 olmal\u0131y\u0131z.<\/p>\n<p>Neyseki hataya dayan\u0131kl\u0131 <em>gRPC<\/em> uygulamalar\u0131 geli\u015ftirebilmek i\u00e7in herhangi bir custom \u00e7\u00f6z\u00fcm \u00fcretmeden <strong><em>gRPC<\/em> <em>retries<\/em><\/strong> \u00f6zelli\u011finden yararlanabilmekteyiz.<\/p>\n<p>Bu \u00f6zellikten yararlanabilmek i\u00e7in <em>gRPC<\/em> client&#8217;\u0131n\u0131, client taraf\u0131nda kay\u0131t ederken temel olarak a\u015fa\u011f\u0131daki gibi bir logic&#8217;e sahip olmam\u0131z gerekmektedir. B\u00f6ylece merkezi d\u00fczeyde ilgili client i\u00e7in retry \u00f6zelli\u011fine sahip olabilmekteyiz.<\/p>\n<pre>var retryMethodConfig = new MethodConfig\r\n{\r\n    Names = { MethodName.Default },\r\n    RetryPolicy = new RetryPolicy\r\n    {\r\n        MaxAttempts = 5,\r\n        InitialBackoff = TimeSpan.FromSeconds(1),\r\n        MaxBackoff = TimeSpan.FromSeconds(5),\r\n        BackoffMultiplier = 1.5,\r\n        RetryableStatusCodes = { StatusCode.Unavailable }\r\n    }\r\n};\r\n\r\nservices.AddGrpcClient&lt;ProductGRPCService.ProductGRPCServiceClient&gt;(o =&gt;\r\n{\r\n    o.Address = new Uri(\"http:\/\/localhost:5000\");\r\n    o.ChannelOptionsActions.Add(opt =&gt; opt.ServiceConfig = new ServiceConfig { MethodConfigs = { retryMethodConfig } });\r\n});<\/pre>\n<p>Bu konu hakk\u0131ndaki daha detayl\u0131 bilgilere ise, <em><a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/grpc\/retries?view=aspnetcore-5.0\" target=\"_blank\" rel=\"noopener\">buradan<\/a><\/em> eri\u015febilirsiniz.<\/p>\n<h2>Toparlayal\u0131m<\/h2>\n<p><em>gRPC,<\/em> <em>Google<\/em> taraf\u0131ndan design edilmi\u015f, servisler aras\u0131nda y\u00fcksek performansl\u0131 bir ileti\u015fim kurabilmemize olanak sa\u011flayan harika bir <em>RPC<\/em> framework&#8217;\u00fcd\u00fcr. &#8220;<em>product.proto<\/em>&#8221; dosyas\u0131nda tan\u0131mlam\u0131\u015f oldu\u011fumuz gibi contractlar bir proto dosyas\u0131 olarak tan\u0131mlanmaktad\u0131r. Bu proto dosyalar\u0131 ise hem server hem de client taraf\u0131 i\u00e7in gerekli olan <em>gRPC<\/em> altyap\u0131s\u0131n\u0131n olu\u015fturulabilmesi ve ileti\u015fimi i\u00e7in kullan\u0131lmaktad\u0131r.<\/p>\n<p><em>gRPC<\/em>, \u00f6zellikle .<em>NET 5<\/em> ile yap\u0131lan iyile\u015ftirme ve optimizasyonlardan sonra olduk\u00e7a harika bir ileti\u015fim se\u00e7ene\u011fi haline gelmektedir. Inter microservice ileti\u015fimi i\u00e7in <em>gRPC<\/em> kullanarak, ileti\u015fim s\u00fcrecini daha efektif, performansl\u0131 ve asynchronous bir hale getirebilmek m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<p>Ayr\u0131ca <em>gRPC<\/em>, &#8220;authentication&#8221;, &#8220;load balancing&#8221; ve &#8220;health checking&#8221; gibi \u00f6zellikleri de desteklemektedir.<\/p>\n<p><em>Source: <a href=\"https:\/\/github.com\/GokGokalp\/mytodostore-net5-grpc-client-streaming\">GokGokalp\/mytodostore-net5-grpc-client-streaming: mytodostore-net5-grpc-client-streaming (github.com)<\/a><\/em><\/p>\n<h2>Referanslar<\/h2>\n<p><em><a href=\"https:\/\/grpc.io\/docs\/what-is-grpc\/core-concepts\/\">Core concepts, architecture and lifecycle | gRPC<\/a><\/em><br \/>\n<a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/grpc\/?view=aspnetcore-5.0\"><em>Introduction to gRPC on .NET | Microsoft Docs<\/em><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>G\u00fcn\u00fcm\u00fcz teknoloji \u00e7a\u011f\u0131n\u0131n ihtiya\u00e7lar\u0131 nedeniyle geli\u015ftirdi\u011fimiz bir \u00e7ok uygulamalar\u0131m\u0131z\u0131, microservice mimarisi \u00e7at\u0131s\u0131 alt\u0131nda distributed olarak geli\u015ftirmeye \u00e7al\u0131\u015f\u0131yoruz. Ayr\u0131ca distributed servisler aras\u0131ndaki ileti\u015fimi ise bir \u00e7ok noktada REST\u00a0 (HTTP JSON) yakla\u015f\u0131m\u0131yla ger\u00e7ekle\u015ftirmeye \u00e7al\u0131\u015f\u0131yoruz. Bu makale kapsam\u0131nda ise gRPC kullanarak servisler aras\u0131nda y\u00fcksek performansl\u0131, stream tabanl\u0131 ileti\u015fimi&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/gokhan-gokalp.com\/tr\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/\">Devam\u0131n\u0131 okuyun<span class=\"screen-reader-text\">.NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":3875,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,505,68,457,368],"tags":[597,526,616,548,613,614,615],"class_list":["post-3837","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net","category-net-core","category-architectural","category-dotnet","category-microservices","tag-net-5","tag-net-core","tag-client-streaming","tag-dotnet-core","tag-grpc","tag-protobuf","tag-streaming","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"tr","enabled_languages":["en","tr"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"tr":{"title":true,"content":true,"excerpt":false}}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>.NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim - G\u00f6khan G\u00f6kalp<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim - G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/\" \/>\n<meta property=\"og:site_name\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-27T08:30:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/grpc-dotnet5-wall.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"675\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"29 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/\"},\"author\":{\"name\":\"G\u00f6khan G\u00f6kalp\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"headline\":\".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim\",\"datePublished\":\"2021-09-27T08:30:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/\"},\"wordCount\":4440,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2021\\\/09\\\/grpc-dotnet5-wall.jpg\",\"keywords\":[\".net 5\",\".net core\",\"client streaming\",\"dotnet core\",\"grpc\",\"protobuf\",\"streaming\"],\"articleSection\":[\".NET\",\".NET Core\",\"Architectural\",\"dotnet\",\"Microservices\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/\",\"name\":\".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim - G\u00f6khan G\u00f6kalp\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2021\\\/09\\\/grpc-dotnet5-wall.jpg\",\"datePublished\":\"2021-09-27T08:30:15+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2021\\\/09\\\/grpc-dotnet5-wall.jpg\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2021\\\/09\\\/grpc-dotnet5-wall.jpg\",\"width\":1200,\"height\":675},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"High-Performance, Stream-Based Communication Between Services with NET 5 and gRPC\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"description\":\"C# &amp; Python lover\",\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gokhan-gokalp.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"pronouns\":\"he\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325\",\"caption\":\"G\u00f6khan G\u00f6kalp\"},\"logo\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325\"},\"sameAs\":[\"https:\\\/\\\/gokhan-gokalp.com\"],\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/tr\\\/author\\\/gok-gokalp\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim - G\u00f6khan G\u00f6kalp","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/","og_locale":"tr_TR","og_type":"article","og_title":".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim - G\u00f6khan G\u00f6kalp","og_url":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/","og_site_name":"G\u00f6khan G\u00f6kalp","article_published_time":"2021-09-27T08:30:15+00:00","og_image":[{"width":1200,"height":675,"url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/grpc-dotnet5-wall.jpg","type":"image\/jpeg"}],"author":"G\u00f6khan G\u00f6kalp","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"G\u00f6khan G\u00f6kalp","Tahmini okuma s\u00fcresi":"29 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#article","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/"},"author":{"name":"G\u00f6khan G\u00f6kalp","@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"headline":".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim","datePublished":"2021-09-27T08:30:15+00:00","mainEntityOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/"},"wordCount":4440,"commentCount":2,"publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/grpc-dotnet5-wall.jpg","keywords":[".net 5",".net core","client streaming","dotnet core","grpc","protobuf","streaming"],"articleSection":[".NET",".NET Core","Architectural","dotnet","Microservices"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/","url":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/","name":".NET 5 ve gRPC ile Servisler Aras\u0131nda Y\u00fcksek Performansl\u0131, Stream Tabanl\u0131 \u0130leti\u015fim - G\u00f6khan G\u00f6kalp","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#primaryimage"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/grpc-dotnet5-wall.jpg","datePublished":"2021-09-27T08:30:15+00:00","breadcrumb":{"@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/"]}]},{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#primaryimage","url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/grpc-dotnet5-wall.jpg","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2021\/09\/grpc-dotnet5-wall.jpg","width":1200,"height":675},{"@type":"BreadcrumbList","@id":"https:\/\/gokhan-gokalp.com\/high-performance-stream-based-communication-between-services-with-net-5-and-grpc\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gokhan-gokalp.com\/"},{"@type":"ListItem","position":2,"name":"High-Performance, Stream-Based Communication Between Services with NET 5 and gRPC"}]},{"@type":"WebSite","@id":"https:\/\/gokhan-gokalp.com\/#website","url":"https:\/\/gokhan-gokalp.com\/","name":"G\u00f6khan G\u00f6kalp","description":"C# &amp; Python lover","publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gokhan-gokalp.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe","name":"G\u00f6khan G\u00f6kalp","pronouns":"he","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325","url":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325","caption":"G\u00f6khan G\u00f6kalp"},"logo":{"@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1777985325"},"sameAs":["https:\/\/gokhan-gokalp.com"],"url":"https:\/\/gokhan-gokalp.com\/tr\/author\/gok-gokalp\/"}]}},"_links":{"self":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/3837","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/comments?post=3837"}],"version-history":[{"count":6,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/3837\/revisions"}],"predecessor-version":[{"id":3883,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/3837\/revisions\/3883"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media\/3875"}],"wp:attachment":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media?parent=3837"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/categories?post=3837"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/tags?post=3837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}