﻿
{"id":26909,"date":"2024-03-22T19:54:37","date_gmt":"2024-03-22T19:54:37","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=26909"},"modified":"2024-03-22T19:54:37","modified_gmt":"2024-03-22T19:54:37","slug":"asp-net-core-signalrda-streaming","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-signalrda-streaming\/","title":{"rendered":"Asp.NET Core &#8211; SignalR&#8217;da Streaming"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>\u00d6nceki yaz\u0131lar\u0131m\u0131zda klavyeye ald\u0131\u011f\u0131m\u0131z <a href=\"https:\/\/www.gencayyildiz.com\/blog\/asp-net-core-signalr-yazi-serisi\/\" rel=\"noopener\" target=\"_blank\">Asp.NET Core \u2013 SignalR<\/a> yaz\u0131 serisinde SignalR teknolojisini s\u00fcrekli tekil mesajlar\u0131n iletimi \u00fczerine ele alm\u0131\u015ft\u0131k. Halbuki SignalR ayn\u0131 zamanda message streaming&#8217;i destekleyen bir yap\u0131ya sahiptir. Evet, iki konum aras\u0131ndaki ak\u0131\u015f s\u0131ras\u0131nda iletilecek mesaja dair t\u00fcm verilerin kullan\u0131labilir olmas\u0131n\u0131 beklemektense, mesaj\u0131n herbir par\u00e7as\u0131n\u0131n\/fragment&#8217;in kullan\u0131labilir hale gelmesiyle client&#8217;a ya da server&#8217;a par\u00e7a par\u00e7a g\u00f6nderilmesi m\u00fcmk\u00fcnd\u00fcr ve bu davran\u0131\u015f client&#8217;tan server&#8217;a ya da server&#8217;dan client&#8217;a olacak \u015fekilde streaming edilebilmektedir. Bu i\u00e7eri\u011fimizde SignalR teknolojisindeki mevzu bahis olan streaming davran\u0131\u015f\u0131n\u0131 masaya yat\u0131racak, <em>Client-to-Server Streaming<\/em> ve <em>Server-to-Client Streaming<\/em> olmak \u00fczere iki farkl\u0131 yakla\u015f\u0131m\u0131 tam teferruatl\u0131 bir \u015fekilde inceliyor olaca\u011f\u0131z.<\/p>\n<h3>Streaming Nedir?<\/h3>\n<p>\u00d6ncelikle incelemede bulunaca\u011f\u0131m\u0131z streaming davran\u0131\u015f\u0131n\u0131n ne oldu\u011funu k\u0131saca izah ederek ba\u015flamakta fayda g\u00f6rmekteyim. Streaming; bir mesaj\u0131 hedef noktaya g\u00f6nderirken b\u00fct\u00fcnsel olarak g\u00f6ndermek yerine par\u00e7alar halinde g\u00f6ndermeyi ifade eden bir kavramd\u0131r. Bu mesaj, k\u00fc\u00e7\u00fck par\u00e7alara ayr\u0131lm\u0131\u015f b\u00fcy\u00fck bir nesne\/veri olabilece\u011fi gibi, her biri farkl\u0131 \u00f6\u011feler olan bir nesne\/veri koleksiyonu da olabilir.<\/p>\n<p>Misal olarak bir dosyan\u0131n server&#8217;dan client&#8217;a g\u00f6nderilmesi streaming ile ger\u00e7ekle\u015ftirilebilir. Dosyan\u0131n tamam\u0131n\u0131 bir seferde belle\u011fe y\u00fcklemek yerine, par\u00e7alan\u0131p g\u00f6nderilmesi bir streaming&#8217;dir ve bu davran\u0131\u015f ile hem bellek kullan\u0131m\u0131 daha etkili hale getirilebilir hem de i\u015flem s\u00fcresi daha da optimize edilebilir.<\/p>\n<h3>Streaming Ne \u0130\u00e7in Kullan\u0131l\u0131r?<\/h3>\n<p>Mant\u0131ken iki farkl\u0131 blo\u011fun haberle\u015fme s\u00fcrecindeki zamansal ve performans a\u00e7\u0131s\u0131ndan do\u011fabilecek maliyetleri daha da t\u00f6rp\u00fclemek i\u00e7in diyebiliriz. D\u00fc\u015f\u00fcnsenize&#8230; Taray\u0131c\u0131 \u00fczerinden bir video izlemek istedi\u011finizde t\u00fcm videonun y\u00fcklenmesini mi bekliyorsunuz? E\u011fer b\u00f6yle bir durum s\u00f6z konusu olsayd\u0131 muhtemelen internetten bir film izleyebilmek i\u00e7in \u00f6ncelikle kayda de\u011fer s\u00fcre boyunca beklenmesi gerekecekti. Lakin videonun tamam\u0131n\u0131n y\u00fcklenmesini beklemek yerine, video k\u00fc\u00e7\u00fck par\u00e7alar halinde indirilmekte ve her par\u00e7a geldik\u00e7e izleme ger\u00e7ekle\u015ftirilmektedir. Bu \u015fekilde hem videonun adil bir s\u00fcre sonraki k\u0131sm\u0131 umrunuzda olmayacak hem de video izleme deneyimi tamamen kesintisiz olacakt\u0131r. Ee haliyle bu tarz bir durumda streaming davran\u0131\u015f\u0131 olmazsa olmazd\u0131r diyebiliriz.<\/p>\n<p>Ya da bir ba\u015fka \u00f6rnek vermemiz gerekirse e\u011fer <em>Kapal\u0131 Devre Televizyon\/Closed-Circuit Television(CCTV)<\/em> kameralar\u0131nda video ak\u0131\u015f\u0131 s\u00fcreklidir. Yani kamera \u00e7ekim yaparken sadece veri par\u00e7alar\u0131n\u0131 al\u0131r ve g\u00f6nderir. \u0130\u015fte bu tarz senaryolarda da streaming tam anlam\u0131yla uygulanabilecek tek senaryodur diyebiliriz.<\/p>\n<h3>SignalR&#8217;da Streaming Davran\u0131\u015f\u0131 Niye?<\/h3>\n<p>Esas\u0131nda streaming deyince akla direkt <a href=\"https:\/\/www.gencayyildiz.com\/blog\/grpc-nedir-ne-amacla-ve-nasil-kullanilir\/\" rel=\"noopener\" target=\"_blank\">gRPC<\/a> geliyor olabilir. Evet, bizler gRPC ile ba\u015far\u0131l\u0131 streaming davran\u0131\u015flar\u0131n\u0131 olduk\u00e7a h\u0131zl\u0131 ve performansl\u0131 bir \u015fekilde ger\u00e7ekle\u015ftirebiliyoruz. Amma velakin SignalR&#8217;da da real-time&#8217;da streaming davran\u0131\u015f\u0131n\u0131 direkt olarak sergilememiz gereken senaryolar olabilir. Tamam, SignalR ile birlikte gRPC&#8217;yi kullanarak streaming&#8217;i uygulayabiliriz. Ama salt bir \u015fekilde gRPC&#8217;ye ihtiya\u00e7 duyulmaks\u0131z\u0131n da bu ihtiyac\u0131 kar\u015f\u0131layabilmekteyiz.<\/p>\n<h3>SignalR \u0130le Client-to-Server Streaming<\/h3>\n<p>Bu ak\u0131\u015f t\u00fcr\u00fcnde, client&#8217;tan server&#8217;a bir stream ba\u015flat\u0131l\u0131r ve bu stream bitene ve sonland\u0131r\u0131lana kadar mesaj g\u00f6nderme i\u015flemi devam eder. Server, mesajlar\u0131 ayn\u0131 \u00e7a\u011fr\u0131 ba\u011flam\u0131nda geldikleri s\u0131rayla edinecek ve mutlak veriyi b\u00fct\u00fcnsel olarak elde edene kadar bu s\u00fcre\u00e7 devam edecektir. Burada \u00f6nemli olan nokta \u015fudur ki, ak\u0131\u015f\u0131 kontrol eden client&#8217;t\u0131r. Tabi server, istedi\u011fi an ak\u0131\u015f\u0131 kapatabilecek bir yetene\u011fe sahiptir ancak normal bir \u015fekilde kapatman\u0131n s\u00f6z konusu olabilmesi i\u00e7in client taraf\u0131ndan bu eylemin gelmesi gerekmektedir.<\/p>\n<p>Client-to-Server Streaming i\u00e7in a\u015fa\u011f\u0131daki gibi Javascript \u00e7al\u0131\u015fmas\u0131 y\u00fcr\u00fct\u00fclebilir.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    const subject = new Subject();\r\n    this.hubConnection.send(&quot;UploadStream&quot;, subject);\r\n    let count = 0;\r\n    const intervalHandle = setInterval(() =&gt; {\r\n      count++;\r\n      subject.next(`Merhaba ${count}`);\r\n      if (count === 10) {\r\n        clearInterval(intervalHandle);\r\n        subject.complete();\r\n      }\r\n    }, 1000);\r\n<\/pre>\n<\/div>\n<p>Burada yap\u0131lan \u00e7al\u0131\u015fmaya g\u00f6z atarsak e\u011fer &#8216;hubconnection&#8217; \u00fczerinden <code>send<\/code> fonksiyonuna \u00e7a\u011fr\u0131da bulunuyor ve sunucudaki <em>UploadStream<\/em> metodunu tetikliyoruz ve b\u00f6ylece bir stream ba\u015flatm\u0131\u015f oluyoruz. Tabi dikkat ederseniz stream&#8217;de bir veri yay\u0131nlayabilmek i\u00e7in RxJS k\u00fct\u00fcphanesinde bulunan <code>Subject<\/code> nesnesinden istifade ediyoruz. Ne zaman ki bu subject&#8217;i complete ederiz, o zaman olu\u015fturulan stream sonland\u0131r\u0131lm\u0131\u015f olacakt\u0131r.<\/p>\n<p><strong>Peki hocam, bu client-to-server stream iste\u011finin kar\u015f\u0131lanmas\u0131 i\u00e7in sunucu taraf\u0131nda nas\u0131l bir \u00e7al\u0131\u015fma yapmal\u0131y\u0131z?<\/strong> diye sordu\u011funuzu duyar gibiyim&#8230; Client&#8217;tan ba\u015flat\u0131lan stream&#8217;i kar\u015f\u0131layabilmek i\u00e7in a\u015fa\u011f\u0131daki gibi <code style=\"color:red;\">ChannelReader&lt;T&gt;<\/code> veya <code style=\"color:red;\">IAsyncEnumerable&lt;T&gt;<\/code> t\u00fcrlerinden parametre alan metotlardan birinin bulundu\u011fu hub s\u0131n\u0131f\u0131n\u0131n tan\u0131mlanmas\u0131 yeterli olacakt\u0131r.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ExampleHub : Hub\r\n    {\r\n        public async Task UploadStream(IAsyncEnumerable&lt;string&gt; stream)\r\n        {\r\n            await foreach (var item in stream)\r\n            {\r\n                Console.WriteLine(item);\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>veya<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ExampleHub : Hub\r\n    {\r\n        public async Task UploadStream(ChannelReader&lt;string&gt; stream)\r\n        {\r\n            while (await stream.WaitToReadAsync())\r\n            {\r\n                await Console.Out.WriteLineAsync(await stream.ReadAsync());\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>SignalR; hub i\u00e7erisinde yukar\u0131daki gibi ilgili parametrelere sahip metotlar\u0131 g\u00f6rd\u00fc\u011f\u00fc an, bunlar\u0131n otomatik olarak client&#8217;tan server&#8217;a stream edilebilir hub metotlar\u0131 oldu\u011funu anlayacakt\u0131r.<\/p>\n<p>Bu yakla\u015f\u0131ma misal olarak bir de .NET client ile \u00f6rneklendirmede bulunabiliriz. \u015e\u00f6yle ki;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.SignalR.Client;\r\n\r\nvar connection = new HubConnectionBuilder()\r\n          .WithUrl(&quot;https:\/\/localhost:7132\/example-hub&quot;)\r\n          .Build();\r\n\r\nawait connection.StartAsync();\r\n\r\nawait connection.SendAsync(&quot;UploadStream&quot;, ClientStreamData());\r\n\r\nasync IAsyncEnumerable&lt;string&gt; ClientStreamData()\r\n{\r\n    for (int i = 0; i &lt; 10; i++)\r\n    {\r\n        await Task.Delay(750);\r\n        yield return $&quot;Merhaba {i}&quot;;\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n<p>ya da a\u015fa\u011f\u0131daki gibi <code style=\"color:red;\">ChannelWriter<\/code> e\u015fli\u011finde de<span style=\"font-size:12px;\">(channel.Writer)<\/span> stream ba\u015flat\u0131l\u0131p, veriler g\u00f6nderilebilir.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.SignalR.Client;\r\nusing System.Threading.Channels;\r\n\r\nvar connection = new HubConnectionBuilder()\r\n          .WithUrl(&quot;https:\/\/localhost:7132\/example-hub&quot;)\r\n          .Build();\r\n\r\nawait connection.StartAsync();\r\n\r\nvar channel = Channel.CreateBounded&lt;string&gt;(10);\r\nawait connection.SendAsync(&quot;UploadStream&quot;, channel.Reader);\r\nfor (int i = 0; i &lt; 10; i++)\r\n{\r\n    await Task.Delay(750);\r\n    await channel.Writer.WriteAsync($&quot;Merhaba {i}&quot;);\r\n}\r\nchannel.Writer.Complete();\r\n<\/pre>\n<\/div>\n<p>Dikkat ederseniz bu y\u00f6ntemde <code>Complete<\/code> metodu ile mesaj g\u00f6nderme i\u015flemi bitti\u011fi taktirde stream tamamlanmaktad\u0131r.<\/p>\n<p>Evet, g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere SignalR ile client-to-server stream y\u00f6ntemini tam teferruatl\u0131 incelemi\u015f bulunuyoruz. \u015eimdi s\u0131ra server-to-client stream y\u00f6ntemine gelmi\u015f bulunmaktad\u0131r. Gelin bu y\u00f6nteminde nas\u0131l bir davran\u0131\u015fa sahip oldu\u011funu ve nas\u0131l yap\u0131land\u0131r\u0131ld\u0131\u011f\u0131n\u0131 incelemeye ba\u015flayal\u0131m&#8230;<\/p>\n<h3>SignalR \u0130le Server-to-Client Streaming<\/h3>\n<p>Server streaming&#8217;de ise ad\u0131ndan da anla\u015f\u0131laca\u011f\u0131 \u00fczere client streaming&#8217;in tam tersi \u015fekilde \u00e7al\u0131\u015fma sergilenmektedir. Client, server \u00fczerinde bir server streaming endpoint&#8217;ini tetiklemesiyle ak\u0131\u015fa subscribe olacakt\u0131r ve ak\u0131\u015f sonlanana kadar mesajlar\u0131 elde etmeye ba\u015flayacakt\u0131r.<\/p>\n<p>Bunun i\u00e7in \u00f6ncelikle server k\u0131sm\u0131nda streaming metodu olu\u015fturulmas\u0131 gerekecektir. SignalR&#8217;da, bir hub i\u00e7erisinde <code style=\"color:red;\">IAsyncEnumerable&lt;T&gt;<\/code>, <code style=\"color:red;\">ChannelReader&lt;T&gt;<\/code>, <code style=\"color:red;\">Task&lt;IAsyncEnumerable&lt;T&gt;&gt;<\/code> veya <code style=\"color:red;\">Task&lt;ChannelReader&lt;T&gt;&gt;<\/code> t\u00fcrlerinde geriye de\u011fer d\u00f6nd\u00fcren metotlar varsa e\u011fer bunlar otomatik olarak streaming metodu olarak de\u011ferlendirilir.<\/p>\n<p>Misal olarak a\u015fa\u011f\u0131da <code style=\"color:red;\">IAsyncEnumerable&lt;T&gt;<\/code> t\u00fcr\u00fcnden geriye d\u00f6n\u00fc\u015f de\u011feri olan bir server hub stream metodu tan\u0131mlanm\u0131\u015ft\u0131r.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ExampleHub : Hub\r\n    {\r\n        public async IAsyncEnumerable&lt;string&gt; DownloadStream(int count, int delay, CancellationToken cancellationToken)\r\n        {\r\n            for (int i = 0; i &lt; count; i++)\r\n            {\r\n                cancellationToken.ThrowIfCancellationRequested();\r\n\r\n                yield return $&quot;Merhaba {i}&quot;;\r\n                await Task.Delay(delay, cancellationToken);\r\n            }\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Burada dikkat ederseniz e\u011fer client&#8217;\u0131n stream&#8217;i iptal edebilmesi i\u00e7in bir <code>CancellationToken<\/code> parametresi tan\u0131mlanabilmektedir. B\u00f6ylece bu parametre arac\u0131l\u0131\u011f\u0131yla client; stream sona ermeden \u00f6nce ba\u011flant\u0131y\u0131 kesebilir, sunucudaki i\u015flemi durdurabilir ve t\u00fcm kaynaklar\u0131 serbest b\u0131rakabilir.<\/p>\n<p>\u015eimdi ayn\u0131 i\u015flemi <code>Channel<\/code>&#8216;lar ile sa\u011flayacak olan hub metodunu olu\u015ftural\u0131m;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ExampleHub : Hub\r\n    {\r\n        public async Task&lt;ChannelReader&lt;string&gt;&gt; DownloadStream(int count, int delay, CancellationToken cancellationToken)\r\n        {\r\n            var channel = Channel.CreateUnbounded&lt;string&gt;();\r\n            for (int i = 0; i &lt; count; i++)\r\n            {\r\n                await channel.Writer.WriteAsync($&quot;Merhaba {i}.&quot;, cancellationToken);\r\n                await Task.Delay(delay, cancellationToken);\r\n            }\r\n            return channel.Reader;\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Tabi burada <code>Channel<\/code>&#8216;lar\u0131n kullan\u0131ld\u0131\u011f\u0131 senaryoda <code>ChannelReader<\/code> return edilene kadar hub \u00e7a\u011fr\u0131lar\u0131 engellenecektir.<\/p>\n<p>Hangi \u00e7al\u0131\u015fma olursa olsun her ikisini de a\u015fa\u011f\u0131daki Javascript \u00e7al\u0131\u015fmas\u0131yla tetikleyebilir ve server tabanl\u0131 streaming&#8217;i ba\u015flatabiliriz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    this.hubConnection.stream(&quot;DownloadStream&quot;, count, delay)\r\n      .subscribe({\r\n        next: item =&gt; {\r\n          console.log(item);\r\n        },\r\n        complete: () =&gt; {\r\n          console.log(&quot;Stream completed&quot;);\r\n        },\r\n        error: error =&gt; {\r\n          console.log(error);\r\n        }\r\n      });\r\n<\/pre>\n<\/div>\n<p>Benzer mant\u0131kla ayn\u0131 streaming&#8217;i a\u015fa\u011f\u0131daki .NET client&#8217;\u0131 \u00fczerinden de t\u00fcketebiliriz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.SignalR.Client;\r\n\r\nvar connection = new HubConnectionBuilder()\r\n          .WithUrl(&quot;https:\/\/localhost:7132\/example-hub&quot;)\r\n          .Build();\r\n\r\nawait connection.StartAsync();\r\n\r\nCancellationTokenSource cancellationTokenSource = new();\r\nvar stream = connection.StreamAsync&lt;string&gt;(&quot;DownloadStream&quot;, 10, 170, cancellationTokenSource.Token);\r\n\r\nawait foreach (var message in stream)\r\n{\r\n    Console.WriteLine(message);\r\n}\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funu incelersek e\u011fer <code>StreamAsync<\/code> fonksiyonu e\u015fli\u011finde server streaming ba\u015flat\u0131lmakta ve bu fonksiyon ile <code style=\"color:red;\">IAsyncEnumerable&lt;T&gt;<\/code> referans\u0131yla \u00e7al\u0131\u015f\u0131lmaktad\u0131r.<\/p>\n<p>Ayr\u0131ca .NET client&#8217;\u0131 a\u015fa\u011f\u0131daki gibi <code>StreamAsChannelAsync<\/code> metoduyla da olu\u015fturabilir ve b\u00f6ylece <code style=\"color:red;\">ChannelReader&lt;T&gt;<\/code> referans\u0131yla da streaming edilen datay\u0131 elde edebiliz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.SignalR.Client;\r\n\r\nvar connection = new HubConnectionBuilder()\r\n          .WithUrl(&quot;https:\/\/localhost:7132\/example-hub&quot;)\r\n          .Build();\r\n\r\nawait connection.StartAsync();\r\n\r\nCancellationTokenSource cancellationTokenSource = new();\r\nvar channel = await connection.StreamAsChannelAsync&lt;string&gt;(&quot;DownloadStream&quot;, 10, 170, cancellationTokenSource.Token);\r\n\r\nwhile (await channel.WaitToReadAsync())\r\n{\r\n    while (channel.TryRead(out var message))\r\n    {\r\n        Console.WriteLine(message);\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n<p>\u0130\u015fte bu kadar basit \ud83d\ude42<\/p>\n<p>Son olarak, bu i\u00e7eri\u011fi haz\u0131rlarken Angular mimarisinde SignalR ile \u00e7al\u0131\u015fmam\u0131z\u0131 kolayla\u015ft\u0131racak olan &#8216;SignalRService&#8217; isimli servisin kaynak kodunu a\u015fa\u011f\u0131da topyek\u00fcn payla\u015fmakta fayda g\u00f6rmekteyim.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n@Injectable({\r\n  providedIn: 'root'\r\n})\r\nexport class SignalRService {\r\n  builder: HubConnectionBuilder = new HubConnectionBuilder();\r\n  hubConnection: HubConnection;\r\n\r\n  async start(hubUrl: string) {\r\n    if (this.hubConnection?.state == HubConnectionState.Connected)\r\n      return this.hubConnection;\r\n\r\n\r\n    hubUrl = `https:\/\/localhost:7132\/${hubUrl}`;\r\n\r\n    this.hubConnection = this.builder.withUrl(hubUrl)\r\n      .withAutomaticReconnect()\r\n      .build();\r\n\r\n    await this.hubConnection.start()\r\n      .then(() =&gt; console.log(&quot;Connected&quot;))\r\n      .catch(error =&gt; {\r\n        console.log(&quot;Connection could not be established&quot;, &quot;a&quot;);\r\n        let interval = setInterval(async () =&gt; {\r\n          await this.hubConnection.start()\r\n            .then(() =&gt; console.log(&quot;Connected&quot;))\r\n            .catch(eror =&gt; console.log(&quot;Connection could not be established&quot;, &quot;b&quot;))\r\n\r\n          if (this.hubConnection.state == HubConnectionState.Connected)\r\n            clearInterval(interval);\r\n        }, 2000);\r\n      });\r\n\r\n    this.hubConnection.onreconnected(connectionId =&gt; console.log(&quot;Reconnected&quot;));\r\n    this.hubConnection.onreconnecting(error =&gt; console.log(&quot;Reconnecting&quot;));\r\n    this.hubConnection.onclose(error =&gt; console.log(&quot;Close reconnection&quot;));\r\n\r\n    return this.hubConnection;\r\n  }\r\n\r\n  async invoke(hubUrl: string, procedureName: string, successCallback?: (value) =&gt; void, errorCallback?: (error) =&gt; void, ...message) {\r\n    await (await this.start(hubUrl)).invoke(procedureName, ...message)\r\n      .then(successCallback)\r\n      .catch(errorCallback);\r\n  }\r\n\r\n  async on(hubUrl: string, procedureName: string, callback: (...message: any) =&gt; void) {\r\n    (await this.start(hubUrl)).on(procedureName, callback);\r\n  }\r\n\r\n  get connectionId() {\r\n    return this.hubConnection.connectionId;\r\n  }\r\n\r\n  send(procedureName: string) {\r\n    const subject = new Subject();\r\n    this.hubConnection.send(procedureName, subject);\r\n    let count = 0;\r\n    const intervalHandle = setInterval(() =&gt; {\r\n      count++;\r\n      subject.next(`Merhaba ${count}`);\r\n      if (count === 10) {\r\n        clearInterval(intervalHandle);\r\n        subject.complete();\r\n      }\r\n    }, 1000);\r\n  }\r\n\r\n  stream(procedureName: string, count: number, delay: number) {\r\n    this.hubConnection.stream(procedureName, count, delay)\r\n      .subscribe({\r\n        next: item =&gt; {\r\n          console.log(item);\r\n        },\r\n        complete: () =&gt; {\r\n          console.log(&quot;Stream completed&quot;);\r\n        },\r\n        error: error =&gt; {\r\n          console.log(error);\r\n        }\r\n      });\r\n  }\r\n}\r\n<\/pre>\n<\/div>\n<p>Bu servis ile Angular uygulamalar\u0131nda SignalR entegrasyon ve yap\u0131land\u0131rmas\u0131n\u0131 rahatl\u0131kla y\u00fcr\u00fctebilir ve kullanabilirsiniz. Ha tabi bu arada bilenler de bilir&#8230; Youtube kanal\u0131m\u0131zda \u00fccretsiz olarak sundu\u011fumuz <a href=\"https:\/\/www.youtube.com\/playlist?list=PLQVXoXFVVtp1DFmoTL4cPTWEWiqndKexZ\" rel=\"noopener\" target=\"_blank\">Mini E-Ticaret E\u011fitim Serisi<\/a>nin front-end k\u0131sm\u0131nda bu servisin temel s\u00fcr\u00fcm\u00fcn\u00fc<span style=\"font-size:12px;\">(bknz: <a href=\"https:\/\/github.com\/gncyyldz\/Mini-E-Ticaret-Client\/blob\/main\/ETicaretClient\/src\/app\/services\/common\/signalr.service.ts\" rel=\"noopener\" target=\"_blank\">signalr.service.ts<\/a>)<\/span> irticalen geli\u015ftirmi\u015f ve kullanm\u0131\u015ft\u0131k. Yukar\u0131da payla\u015ft\u0131\u011f\u0131m kaynak ise ilgili e\u011fitimdekinden daha da geli\u015ftirilmi\u015f, hatalar\u0131 onar\u0131lm\u0131\u015f ve SignalR&#8217;\u0131n son yeteneklerine e\u015flik edebilecek \u00f6zellikleri bar\u0131nd\u0131rabilir bir \u015fekilde tasarlanm\u0131\u015ft\u0131r.<\/p>\n<p>B\u00f6ylece i\u00e7eri\u011fimiz boyunca SignalR kapsam\u0131nda var olan streaming \u00f6zelli\u011fini incelemi\u015f bulunuyor ve client-to-server ve server-to-client  davran\u0131\u015flar\u0131n\u0131n nas\u0131l sa\u011flanaca\u011f\u0131n\u0131 Javascript ve .NET client&#8217;lar\u0131 e\u015fli\u011finde de\u011ferlendirmi\u015f bulunuyoruz.<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, \u00d6nceki yaz\u0131lar\u0131m\u0131zda klavyeye ald\u0131\u011f\u0131m\u0131z Asp.NET Core \u2013 SignalR yaz\u0131 serisinde SignalR teknolojisini s\u00fcrekli tekil mesajlar\u0131n iletimi \u00fczerine ele alm\u0131\u015ft\u0131k. Halbuki SignalR ayn\u0131 zamanda message streaming&#8217;i destekleyen bir yap\u0131ya sahiptir. Evet, iki konum aras\u0131ndaki&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":17653,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4912,2739,3760],"tags":[5025,5028,5029,5026,5024,3031,5023,5027,639,5020,5021,5022],"class_list":["post-26909","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-net-8","category-net-core","category-signalr","tag-cctv","tag-channelreader","tag-channelwriter","tag-client-to-server-streaming","tag-closed-circuit-television","tag-iasyncenumerable","tag-kapali-devre-televizyon","tag-server-to-client-streaming","tag-signalr","tag-signalr-streaming","tag-streaming","tag-streaming-nedir"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26909","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=26909"}],"version-history":[{"count":13,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26909\/revisions"}],"predecessor-version":[{"id":26924,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/26909\/revisions\/26924"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/17653"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=26909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=26909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=26909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}