SignalR Chatting ASP.Net Core,Angular

Let’s create a real-time chatting application(SignalR) with ASP.Net Core and Angular with this post. In my previous post SignalR was implemented using ASP.Net MVC, please have an overview if needed by following the link: https://shashangka.com/2017/12/30/user-specific-notifications-using-asp-net-mvc-signalr/ .

ASP.NET Core SignalR :

According to Microsoft docs, ASP.NET Core SignalR is an open-source library that simplifies adding real-time web functionality to apps. Real-time web functionality enables server-side code to push content to clients instantly.

Server Side:

Let’s get started creating and configure server side application by Visual Studio 2019.

Package Installation:

After successfully creating the application, install latest package from NuGet:

Microsoft.AspNetCore.SignalR.Core

SignalR Hub:

SignalR Hub is basically centre of client server communication. Below is the hub class.

public class ChatHub : Hub
{
    private readonly static ConnectionMapping _connections = new ConnectionMapping();
    public DataAccess _objData = null;

    public async Task SendMessage(vmMessage _message)
    {
        //Receive Message
        List ReceiverConnectionids = _connections.GetConnections(_message.Receiverid).ToList();
        if (ReceiverConnectionids.Count() > 0)
        {
            //Save-Receive-Message
            try
            {
                _objData = new DataAccess();
                _message.IsPrivate = true;
                _message.Connectionid = String.Join(",", ReceiverConnectionids);
                await _objData.saveUserChat(_message);
                await Clients.Clients(ReceiverConnectionids).SendAsync("ReceiveMessage", _message);
            }
            catch (Exception) { }
        }
    }


    public override async Task OnConnectedAsync()
    {
        var httpContext = Context.GetHttpContext();
        if (httpContext != null)
        {
            try
            {
                //Add Logged User
                var userName = httpContext.Request.Query["user"].ToString();
                //var UserAgent = httpContext.Request.Headers["User-Agent"].FirstOrDefault().ToString();
                var connId = Context.ConnectionId.ToString();
                _connections.Add(userName, connId);

                //Update Client
                await Clients.All.SendAsync("UpdateUserList", _connections.ToJson());
            }
            catch (Exception) { }
        }
    }

    public override async Task OnDisconnectedAsync(Exception exception)
    {
        var httpContext = Context.GetHttpContext();
        if (httpContext != null)
        {
            //Remove Logged User
            var username = httpContext.Request.Query["user"];
            _connections.Remove(username, Context.ConnectionId);

            //Update Client
            await Clients.All.SendAsync("UpdateUserList", _connections.ToJson());
        }

        //return base.OnDisconnectedAsync(exception);
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.MapHub("/chathub");
    });
}

Client Side:

After completing server side work, let’s configure client side angular application.

Package Installation:

Go to package.json file to add SignalR client package:

/signalr": "1.1.4

Copy library to wwwroot folder by using gulp task below:

gulp.src('./node_modules//signalr/dist/browser/**/*.+(js|js.map)')
    .pipe(gulp.dest(root_path.package_lib + 'signalr'));

Open index.html to linkup library.

Chat Component:

import { Component, OnInit, ElementRef, ViewChild, EventEmitter, OnDestroy } from '/core';
import { FormBuilder, FormGroup, FormControl, Validators } from '/forms';
import { Title } from '/platform-browser';
import { DataService } from '../../shared/service';
import { Paging } from '../../shared/paging';
import { Message } from '../../shared/models/message';
declare var signalR: any;

({
    selector: 'app-chat',
    templateUrl: './app/backoffice/chat/component.html',
    providers: [DataService, Paging]
})

export class ChatComponent implements OnInit, OnDestroy {
    public title: any;
    public res: any;
    public resmessage: string;
    public loggedUserid: number = 0;
    public loggedUsername: string;

    //API
    public _chatUrl: string = 'api/chat/userChat';

    //Chat
    public onlineUser: any = [];
    public chatUsername: string = null;
    public chatConnection: string;
    public chatMessages: any = [];
    public chatMessage: Message = null;
    public _hubConnection;

    constructor(
        private titleService: Title,
        private _dataService: DataService) {
        var loggedUser = JSON.parse(localStorage.getItem('loggedUser'));
        this.loggedUsername = loggedUser.userName;
        this.loggedUserid = loggedUser.userId;
    }

    ngOnInit() {
        this.titleService.setTitle("Chat");
        this.signalrConn();
    }

    signalrConn() {
        //Init Connection
        this._hubConnection = new signalR.HubConnectionBuilder().withUrl("http://localhost:63742/chatHub?user=" + this.loggedUsername).build();

        //Call client methods from hub to update User
        this._hubConnection.on('UpdateUserList', (onlineuser) => {
            var users = JSON.parse(onlineuser);
            this.onlineUser = [];
            for (var key in users) {
                if (users.hasOwnProperty(key)) {
                    if (key !== this.loggedUsername) {
                        this.onlineUser.push({
                            userName: key,
                            connection: users[key]
                        });
                    }
                }
            }
        });

        //Call client methods from hub to update User
        this._hubConnection.on('ReceiveMessage', (message: Message) => {
            this.chatUsername = message.senderid;
            this.chatLog();
        });

        //Start Connection
        this._hubConnection
            .start()
            .then(function () {
                console.log("Connected");
            }).catch(function (err) {
                return console.error(err.toString());
            });
    }

    sendMessage(message) {
        //Send Message
        if (message != '') {
            this.chatMessage = new Message();
            this.chatMessage.senderid = this.loggedUsername;
            this.chatMessage.receiverid = this.chatUsername;
            this.chatMessage.message = message;
            this.chatMessage.messagestatus = "sent";
            this.chatMessages.push(this.chatMessage);
            this._hubConnection.invoke('SendMessage', this.chatMessage);
        }
    }

    chooseUser(user) {
        this.chatUsername = user.userName;
        this.chatLog();
    }

    chatLog() {
        //ChatLog
        var param = { Senderid: this.loggedUsername, Receiverid: this.chatUsername };
        var getchatUrl = this._chatUrl + '?param=' + JSON.stringify(param);
        this._dataService.get(getchatUrl)
            .subscribe(
                response => {
                    this.res = response;
                    if (this.res != null) {
                        var chatLog = this.res.resdata;
                        this.chatMessages = [];
                        if (chatLog.length > 0) {
                            for (var i = 0; i < chatLog.length; i++) {
                                if (this.loggedUsername === chatLog[i].senderid) {
                                    chatLog[i].messagestatus = "sent";
                                }
                                else {
                                    chatLog[i].messagestatus = "received";
                                }

                                //Push-Data
                                this.chatMessages.push(chatLog[i]);
                            }
                        }
                    }
                }, error => {
                    console.log(error);
                }
            );
    }

    ngOnDestroy() {
        //Stop Connection
        this._hubConnection
            .stop()
            .then(function () {
                console.log("Stopped");
            }).catch(function (err) {
                return console.error(err.toString());
            });
    }
}

Component Html:

SignalR Messaging

Online Users

{{chatUsername}}


0">
{{msg.senderid}} | {{msg.messagedate | date : "shortTime"}}

{{msg.message}}

{{msg.message}}

No Message Found..

Finally:

Let’s run both application to test messaging operation. As we can see from below image how our real-time chatting application is working.

Download/clone full source code from  Hope this will help 🙂

Author:

Since March 2011, have 8+ years of professional experience on software development, currently working as Senior Software Engineer at s3 Innovate Pte Ltd.

5 thoughts on “SignalR Chatting ASP.Net Core,Angular”

Leave a Reply