ASP.NET Core 2.0 SignalR – Basit Chat
Selamlar arkadaşlar,
Bu makalede macOS Sierra işletim sisteminde, .Net Core 2.0 ile bir Mvc projesinde, signalR kullanarak basit bir chat uygulaması yazacağız. Öncelikle baştan belirteyim, .net Core için signalR kütüphanesi bu makale yazılırken halen “1.0.0-alpha2-final” versiyonunda bulunmaktadır.
Peki kısaca signalR nedir ? Real Time yani canlı işlemler yapılmak için kullanılan bir socket teknolojisidir. Örneğin bir web sayfasında, canlı maç skoru bilgisinin client’ın herhangi bir servisi ya da yapıyı dinlemeden hatta sayfa refresh olmadan değiştirilmek istendiğinde, kullanılabilecek teknolojilerden sadece biridir.
Öncelikle gelin .Net Core Mvc projemizi oluşturalım. İlgili kurulumlar yapıldıktan sonra : Bash ortamında “dotnet new mvc -o signalRCore” yazılarak ilgili proje yaratılır.
- Oluşan Mvc projede “signalRCore.csproj” dosyası aşağıdaki gibi güncellenir. ==>”<PackageReference Include=”Microsoft.AspNetCore.SignalR” Version=”1.0.0-alpha2-final” />” dosyası eklenir. Kaydetme işleminden sonra VS Code’un sorduğu Restore işlemine izin verilir. Ya da “dotnet restore” komutu gerek olmasa da çalıştırılabilir.
- “<Folder Include=”wwwroot\scripts\” />” : Aşağıda görülen bu ekleme ile “.cshtml” sayfa üzerinde eklenecek script dosyalarına kısa yol verilmiş olunur.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-alpha2-final" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /> <Folder Include="wwwroot\scripts\" /> </ItemGroup> |
HomeController.cs : Aşağıda görüldüğü gibi Index() action’ına hiçbir değişiklik yapılmadan ilgili View’ın gelmesi sağlanmıştır.
Chat: Hub class’ı : Hub “Microsoft.AspNetCore.SignalR” namespace’i altında bulunan, real time socket işlemlerinin yapıldığı signalR sınıfıdır.
- “OnConnectedAsync()” : Methodu ile, client sayfayı ilk açtığı an, Chat Hub sınıfına connect olunur ve tam bu esnada bir ConnectionID alınır. Aslında bu her bir client için tekil oluşan bir tanımlayıcıdır. İşte tam bu anda devreye giren method “OnConnectedAsync()” methodudur. Burada herbir client için unique oluşturulan ConnectionID alınıp, tekrar ilgili client’ın kendisine gönderilir. Kısaca bir client spesific bir başka client’a bir bildiri gönderecek ise, aynı bir mail adresi veya telefon numarası gibi bu connectionID’ye ihtiyaç duymaktadır.
- “Clients.Client” : SignalR sınıfına connect olan herhangi bir client’ı belirtmektedir.
- “Clients.Client(Context.ConnectionId)“: Spesifik olarak connect olan client’ı temsil etmektedir.
- “.InvokeAsync(“SetConnectionId”,Context.ConnectionId)” : Methodu ile client tarafındaki “SetConnectionId()” function’ı tetiklenmiş ve parametre olarak, ilgili client’a ait “Context.ConnectionId” gönderilmiştir. Burası bence signalR’ın en büyük gücüdür. Tekrarlamak gerekir ise Server Side Taraftan ==> Client Side Tarafdaki bir Function() tetiklenmişti.
- “SendMessage(string message)“: Connect olan tüm clientlara yazlmış olan mesajın gönderilmesi için kullanılan methoddur.
- “Clients.All”: Tüm clientları temsil etmektedir.
- “Clients.All.InvokeAsync(“GetMessage”, message)” : Hub sınıfına bağlı olan tüm clientlara, front taraftaki “GetMessage()” function’ı, server side taraftan parametre olarak gönderilemek istenen string mesaj değişkeni ile tetiklenir. Client Side ==> Her bir client’ın açtığı browser ekranı anlamına gelmektedir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using signalRCore.Models; namespace signalRCore.Controllers { //npm install jquery public class HomeController : Controller { public IActionResult Index() { return View(); } } public class Chat : Hub { public override Task OnConnectedAsync(){ return Clients.Client(Context.ConnectionId).InvokeAsync("SetConnectionId",Context.ConnectionId); } public Task SendMessage(string message) { return Clients.All.InvokeAsync("GetMessage", message); } } } |
Not : Alttaki resimde signalR için kodlar biraz eskide kalsa da, mantık hep aynıdır. SignalR kısaca, server side tarafdan client side tarafdaki bir function’ın çağrılmasıdır. Aynı şekilde client side taraftan, server side tarafdaki bir method da çağrılabilir. Ama bu zaten pek de alışık olmadığımız bir durum değildir :)
Startup.cs: Aşağıdaki gibi düzenlenir. Asp.Net Core’da en başta herşey ham hali ile başlar. Amaç performans ve gereksiz hiçbir nesnenin bulunmayışının istenmesidir. Bu neden ile :
- ConfigureServices() methodunda gerekli tüm servisler burada tanımlanır.==> services.AddMvc() ve services.AddSignalR() methodları eklenerek, projenin bir Mvc projesi olması ve SignalR kütüphanesinin bu projede kullanılacağı tanımlanmıştır.
- Configure() methodunda bir takım ayarlamalar yapılır.
- app.UseStaticFiles() : Proje içinde static dosyaların kullanılması sağlanır(wwwroot altında). Örnek resim dosyaları,script dosyaları gibi..
- app.UseMvc(routes => : Mvc routing tanımlamalarının yapıldığı yerdir.
- app.UseSignalR(routes => : “chat” sınıfının SignalR sınıfı olarak “chat” adı ile tanıtıldığı yerdir ==>”routes.MapHub<Chat>(“chat”);“
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using signalRCore.Controllers; namespace signalRCore { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddSignalR(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); app.UseSignalR(routes => { routes.MapHub<Chat>("chat"); }); } } } |
Program.cs : “dotnet run” komutu çalıştırıldığında, uygulamanın ayağa kalktığı default port 5000‘dir. Bunun istendiği gibi değiştirildiği yer, uygulamanın ilk ayağa kalktığı Program.cs sınıfıdır.
- void Main() : İlk çalıştırılan methoddur.
- BuildWebHost() : İlgili methodda host işlemi ile web sayfası ayağa kaldırılırken ==> “UseUrls(“http://localhost:1453”)“ komutu ile 5000 default portu 1453 olarak değiştirilmiştir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace signalRCore { public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseUrls("http://localhost:1453") .Build(); } } |
Index.cshtml: Genel mesajlaşma işleminin yapıldığı ekrandır.
- Dikkat edilir ise artık signalR’da önceden kullandığımız magic script denilen “<script src=”/signalr/hubs”></script>” kullanılmamaktadır.
- Signalr, kendi içerisinde artık Jquery’e ihtiyaç duymamaktadır. Yehuuu :) Aşağıda kullanılma nedeni, custom kullanılan functionlardır. Kısaca signalR değil ben kullandım :)
- Sayfanın başında signalR için gerekli client script yanda görüldüğü gibi eklenmiştir.==>”<script src=”scripts/signalr-client-1.0.0-alpha2-final.min.js”></script>”
- İlgili signalR script kütüphanesi “npm install @aspnet/signalr-client –save” komutu ile indirilebilir.
- “npm install @aspnet/signalr-client” komutu ile ilgili kütüphane, golbal’e de indirilebilir. İlgili dosya globalde yandaki klasörden erişilebilir==>”/usr/local/lib/node_modules/@aspnet/signalr-client/dist/browser/signalr-client-1.0.0-alpha2-final.min.js“. Bu script dosyasının projede “wwwroot” altında “scripts” klasörü altına kopyalanması gerekmektedir.
- “let connection = new signalR.HubConnection(‘/chat’)“: signalR Chat hub sınıfına bağlanılır.
- “connection.on(‘GetMessage‘, data => {” : Client Side tarafda signalR için function’ın yeni tanımlama şekli budur. “GetMessage()” functionın da, kendisine server side’dan gönderilen mesajları “messageList” id değerine sahip textare’ya eklemektedir.
- “connection.on(‘SetConnectionId‘, data => {” : Client’ın ilk connect olması durumunda, server side tarafındaki “OnConnectedAsync()” methodunda, ilgili bağlanan user’ın browserında çağrılan client side functiondır. Yani, server side taraftan ==> client side tarafa doğru tetiklenen bir functiondır.
- “connection.start()” : Ilgili Chat hub sınıfına bağlanıldığı kısımdır. Bu işlmeden sonra “OnConnectedAsync” methodu tetiklenir ve yeni bağlanan user’ın client side tarafındaki SetConnectionId() function’ı tetiklenerek, yeni alınan ConnectionID konsola yazılır.
- “function SendMessage(){” : Bu functionda da client side taraftan ==> server side tarafa doğru bir tetikleme mevcuttur. Yazılan mesajın tüm clientlara gönderilmesi için server side taraftaki “SendMessage()” methodu, yazılan text parametresi ile birlikte tetiklenir. “textarea”‘daki text mesajın değerinin alınması için $ jquery kullanılmıştır. Yoksa artık signalR paketinin jquery’e ihtiyacı yoktur :)
- “$(document).ready(function() {” : Bu jquery methodunda, sayfa yüklemesi yani render işlemi tamamlandığı zaman, içine mesaj yazılan textarea’ya “keypress()” eventi ile bağlanılır. Bu işlemde eğer basılan tuş “e.which==13” ==> Enter ise “SendMessage()” methodu çağrılır. Yani ilgili mesaj tüm clientlara gönderilir.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<head> <script src="scripts/signalr-client-1.0.0-alpha2-final.min.js"></script> <script src="scripts/jquery.min.js"></script> <script> let connection = new signalR.HubConnection('/chat'); connection.on('GetMessage', data => { if($('#messageList').val().length>0){ $('#messageList').append("\n"+data); } else{ $('#messageList').append(data); } }); connection.on('SetConnectionId', data => { console.log("ConnectionID : "+data); }); connection.start() function SendMessage(){ var text=$('#message').val(); $('#message').val(""); var message=$.trim(text); connection.invoke('SendMessage', message); } $(document).ready(function() { $('#message').focus(); $('#message').keypress(function(e) { if(e.which == 13) { SendMessage(); } }); }); </script> </head> <body> <div class="container"> <div class="jumbotron"> <h3>.Net Core 2.0 SignalR & Mvc</h3> </div> <hr> <b><i>Mesaj :</i></b><input type="text" id="message" style="width: 525px; padding: 2px; border: 1px solid rgb(18, 178, 241)"> <input type="button" onclick="SendMessage()" value="Gönder" class="btn btn-success"> <textarea cols=90 rows="15" id="messageList"></textarea> </div> </body> |
Bu makalede kısaca, signalR socket’in .Net Core ile cross platformda nasıl kullanıldığını, kurulumunu ve yapılması gereken configuration işlmelerini, basit bir chat uygulaması üzerinde inceledik.
Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hoşçakalın. Proje kodlarına aşağıdaki linkden ulaşabilirsiniz.
Source Code : https://github.com/borakasmer/.NetCore-SignalR-Basic-Chat
hocam teşekkürler güzel paylaşım olmuş
Ben teşekkür ederim..
Hocam selamlar,
SignalR’ı çeşitli işlemlerde sıklıkla kullanıyorum, veri güncellemelerinde, login işlemlerinde yönetici tarafına mesaj göndererek vs. merak ettiğim chat uygulamasında kullanıcı bazlı işlem yapmak mümkünmüdür örneğin connectionId, sini aldığımız her kullanıcıya, kişi bazlı mesaj gönderme olanağı sunuyormu?
Saygılar.
Merhaba, diğer makalelerinizden yola çıkarak mümkün olduğunu gördüm. küçükte bir uygulama geliştirdim, sıkıntı yok :)
iyi çalışmalar dilerim.
İyi çalışmalar.
Selamlar,
Evet kişi bazlı mesaj atabiliyoruz Zekeriya. Client bazlı signalR connectionID ile.
public async override Task OnConnected()
{
await Clients.Caller.connected(Context.ConnectionId);
}
Örnek makale :
http://www.borakasmer.com/signalr-chatlesme-sirasinda-yazismalari-rabbitmq-kullanilarak-sql-servera-kaydetme-bolum1/
İyi çalışmalar.
Hocam selamlar, öncelikle paylaşımlarınız için teşekkürler.
Angular da browser üzerinden url den parametre gönderilmesini engelleyip sadece bir button ile routerLink aracılığıyla parametre nasıl gönderirim yardımcı olur musunuz ?
Merhaba hocam,
asp.net core 2.1 ile signalr teknolojisini kullanmak istediğimde aşağıdaki gbi bir hata alıyorum.
Error: Failed to start the connection. Error: No available transports found.
ConsoleLogger.log @ signalr.js:1744
(anonymous) @ signalr.js:1903
step @ signalr.js:1816
(anonymous) @ signalr.js:1797
fulfilled @ signalr.js:1788
Promise.then (async)
step @ signalr.js:1790
(anonymous) @ signalr.js:1791
__awaiter @ signalr.js:1787
HttpConnection.startInternal @ signalr.js:1851
(anonymous) @ signalr.js:1845
step @ signalr.js:1816
(anonymous) @ signalr.js:1797
(anonymous) @ signalr.js:1791
__awaiter @ signalr.js:1787
HttpConnection.start @ signalr.js:1839
(anonymous) @ signalr.js:2347
step @ signalr.js:2232
(anonymous) @ signalr.js:2213
(anonymous) @ signalr.js:2207
__awaiter @ signalr.js:2203
HubConnection.start @ signalr.js:2338
(anonymous) @ chat:128
signalr.js:1930 Uncaught (in promise) Error: No available transports found.
at HttpConnection.createTransport (signalr.js:1930)
at HttpConnection. (signalr.js:1884)
at step (signalr.js:1816)
at Object.next (signalr.js:1797)
at fulfilled (signalr.js:1788)
Selam,
Program.cs’e alttaki satırı ekleyip denermisin! “signalR” erişim yolunu ve bunun gibi diğer Url’leri de buna göre değiştirmeyi unutma.
.UseUrls(“http://localhost:5000”)
İyi çalışmalar.
Bora hocam signalr örnekleri hep client dan diğer client’a veya server’dan client’lara şeklinde.Ben webclient’dan winform server’a mesaj göndermek istiyorum nasıl yapabilirim acaba?Bunu yapmaktaki amacım kullanıcının istediği web sayfası üzerinden istediği yazıcıya direkt yazılacak veriyi gönderebilmek.
Selam Mehmet,
O zaman DB, RabbitMQ veye Redis gibi bir microservis kullanarak bir channel’a print() komutunu gönderirsin. Bu channel’ı windows makinada da dinleyerek, istenen işlemi yapabilirsin.
İyi çalışmalar.
Javascript ile bağlanabilmek için Hub bağlantısı localhost’da olmak zorunda mı? Yani client ayrı server ayrı uygulama olduğunda nasıl bir değişiklik gerekiyor.
Selamlar,
Hayır olması gerekli değil.
Hub ayrı bir serverda olur ise, IP’si ile erişiyorsununuz. Önceki makalelerimde bir örneği olacaktı.
İyi çalışmalar.
Teşekkürler