SignalR در ASP.NET Core

در این مقاله قصد داریم SignalR که یکی از کتابخانه Net. مایکروسافت است و برای پیاده سازی وب سایت های real-time است را در ASP.NET Core به شما معرفی کنیم و نحوه استفاده از آن را به شما آموزش دهیم.

SignalR  در ASP.NET Core

SignalR  یک کتابخانه Net. مایکروسافت است که برای پیاده سازی وب سایت های real-time استفاده میشود.SignalR   از چندین تکنیک برای دستیابی به ارتباط  bi-directional بین سرور و کاربر استفاده میکند.سرورها می توانند پیام ها را به مشتریان متصل در هر زمان push  کنند.SignalR   در نسخه پیشین Asp.Net Core  در دسترس بود و در حال حاضر یک نسخه پیش انتشار برای ASP.NET Core ساخته شده است.

نصب و راه اندازی

شما نیاز دارید که پکیج های Microsoft.AspNetCore.SignalR.Client  و Microsoft.AspNetCore.SignalR را برای نسخه پیش انتشار از طریق Nuget نصب کنید.همچنین شما به (NPM (Node Package Manager نیز نیاز دارید.

پس از نصب NPM ، شما نیاز دارید که پکیج  aspnet/signalr-client@ را دریافت کنید و پس از آن شما باید فایل

 signalr-client-1.0.0-alpha1-final.js را از فولدر node_modules\@aspnet\signalr-client\dist\browser دریافت کنید و قرار دهید و آن را در جایی زیر پوشه wwwroot قرار دهید تا بتوانید آن را از صفحات خود ارجاع دهید.سپس ، ما باید سرویس های مورد نیازمان را قبل استفاده در ConfigureServices ثبت کنیم.

services.AddSignalR();

ما یک برنامه چت ساده را پیاده سازی خواهیم کرد ، بنابراین ما یک chat hub در متد Configure معرفی خواهیم کرد:

app.UseSignalR(routes =>
{
    routes.MapHub<ChatHub>("chat");
});

توجه داشته باشید: UseSignalR باید قبل از UseMvc فراخوانی شود!شما این کار را برای هر تعداد هاب در صورت داشتن چند نقطه پایانی  میتوانید انجام دهید.

به view یا فایل layout خود ، signalr-client-1.0.0-alpha1-final.js را رفرنس بدهید.

<script src="libs/signalr-client/signalr-client-1.0.0-alpha1-final.js"></script>

 پیاده سازی یک هاب

هاب یک کلاس است که از Hub ارثبری کرده است.در داخل آن متد هایی را که ممکن است به وسیله جاوا اسکریپت فراخوانی شوند را اضافه میکنید.از آن جاییکه ما میخواهیم یک هاب چت را پیاده سازی کنیم ، به صورت زیر داریم:

public class ChatHub : Hub
{
    public async Task Send(string message)
    {
        await this.Clients.All.InvokeAsync("Send", message);
    }
}

همانطور که می بینید ، ما یک متد تک به نام Send داریم که به عنوان مثال یک پارامتر تکی به نام message دریافت میکند.

شما لازم نیست پارامترهای مشابه این را برای فراخوانی broadcast  یا (InvokeAsync) ارسال کنید ، شما می توانید هر آنچه که می خواهید را ارسال کنید.به سمت کلاینت میرویم ، این کد را پس از رفرنس به فایل SignalR JavaScript اضافه کنید:

 <script>
     
        var transportType = signalR.TransportType.WebSockets;
        //can also be ServerSentEvents or LongPolling
        var logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
        var chatHub = new signalR.HttpConnection(`http://${document.location.host}/chat`, { transport: transportType, logger: logger });
        var chatConnection = new signalR.HubConnection(chatHub, logger);
     
        chatConnection.onClosed = e => {
            console.log('connection closed');
       };
    
       chatConnection.on('Send', (message) => {
           console.log('received message');
       });
    
       chatConnection.start().catch(err => {
           console.log('connection error');
       });
    
       function send(message) {
           chatConnection.invoke('Send', message);
       }
    
</script>

به نکات زیر توجه داشته باشید:

1.اتصال ایجاد شده که اشاره به آدرس فعلی به علاوه پسوند چت ، همان چیزی است که در Call MapHub ثبت کرده ایم.

2.به وسیله یک حمل و نقل خاص مقدار دهی اولیه میشود ، در این مورد ، WebSocket ها ، اما این لازم نیست ، یعنی شما میتوانید اجازه دهید SignalR تصمیم بگیرد که برای خود چه کار کند؛

برای بعضی از سیستم عامل های مانند ویندوز 7، شما ممکن است قادر به استفاده از WebSockets نباشید ، بنابراین شما باید بین LongPolling یا ServerSentEvents انتخاب کنید.

3.connection نیاز دارد تا با فراخوانی start مقدار دهی اولیه شود

4.یک handler برای متد Send با همان تک پارامتری که متد Send  در داخل  ChatHub’s دریافت میکند ، داریم.

ممکن است ارسال پارامترهای رشته جستجو دلخواه باشند که بعدا در یک هاب گرفتار میشوند ، در واقع ، این تنها راه برای ارسال داده به هاب است:

var chatHub = new signalR.HttpConnection(`http://${document.location.host}/chat?key=value`, { transport: transportType, logger: logger });

در سمت سرور از این استفاده میکنیم :

var value = this.Context.Connection.GetHttpContext().Request.Query["key"].SingleOrDefault();

بنابراین هر زمان که کسی به این صفحه دسترسی پیدا می کند و تابع send  جاوا اسکریپت را فراخوانی کند، متد Send را در کلاس ChatHub فراخوانی می کند.این کلاس اساسا این پیام را برای همه مشتریان متصل پخش می کند.همچنین امکان ارسال پیام به یک گروه خاص نیز وجود دارد:

await this.Clients.Group("groupName").InvokeAsync("Send", message);

 یا به یک مشتری خاص:

await this.Clients.Client("id").InvokeAsync("Send", message);

شما میتوانید یک کاربر که توسط connection id وClaimsPrincipal شناسایی شده است اضافه کنید ، اگر احراز هویت استفاده میکنید به صورت زیر عمل میکنید:

public override Task OnConnectedAsync()
{
    this.Groups.AddAsync(this.Context.ConnectionId, "groupName");

    return base.OnConnectedAsync();
}

بله، OnConnectedAsync هر بار که یک کاربر جدید متصل می شود، فراخوانی می شود و یک متد مشابه با نام  OnDisconnectedAsync موجود است برای زمانی که کاربر قطع می شود:

public override Task OnDisconnectedAsync(Exception exception)
{
    return base.OnDisconnectedAsync(exception);
}

اگر در هنگام قطع شدن ارتباط استثنایی وجود داشته باشد ، پارامتر استثنا باید non-null باشد.خاصیت Context دو ویژگی، ConnectionId و User را ارائه می دهد.User  زمانی تنظیم میشود که کاربر تایید شده باشد ، اما ConnectionId  همیشه تنظیم میشود و همان کاربر تغییر نمیکند.یک مثال دیگر ، تصور کنید که میخواهید timer tick ها را به تمام کاربران متصل از طریق تایمر هاب ارسال کنید.شما می توانید این ها را در متد Configure انجام دهید:

TimerCallback callback = (x) => {
    var hub = serviceProvider.GetService<IHubContext<TimerHub>>();
    hub.Clients.All.InvokeAsync("Notify", DateTime.Now);
};

var timer = new Timer(callback);
timer.Change(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(10));

در اینجا ما یک تایمر را راه اندازی می کنیم و از آنجا می توانیم به timer hub رفرنس دهیم و متد اعلان آن را با برچسب زمانی فعلی فراخوانی کنیم.

کلاس TimerHub فقط کد زیر است.

public class TimerHub : Hub
{
}

توجه داشته باشید که این کلاس هیچ متد عمومی ندارد ، چون به معناست که قابل خواندن توسط جاوا اسکریپت نیست ، بلکه فقط برای خارج از ارسال پیام استفاده می شود.

ارسال پیام (Messages) به هاب

در نهایت، امکان ارسال پیام از خارج به یک هاب نیز وجود دارد.هنگامیکه از کنترلر استفاده میکنیم ، شما باید یک نمونه از  IHubContext<ChatHub> را به آن تزریق کنید ، از این شما میتوانید پیام هایتان را به هاب ارسال کنید ،  که بعدا در صورت لزوم پخش می شود:

private readonly IHubContext<ChatHub> _context;

[HttpGet("Send/{message}")]
public IActionResult Send(string message)
{
    //for everyone
    this._context.Clients.All.InvokeAsync("Send", message);
    //for a single group
    this._context.Clients.Group("groupName").InvokeAsync("Send", message);
    //for a single client
    this._context.Clients.Client("id").InvokeAsync("Send", message);

    return this.Ok();
}