Create chat application using signalr with database in asp.net
12:05Introduction
In this articales I want to show how to chatting in asp.net using SignalR. I show how to do a public and private chat. The chatting data will store in the database. We see our previous chat by scrolling as like as facebook.What is SignalR?
ASP.NET SignalR is a library that simplifies the process of adding real-time web functionality to applications. SignalR connected clients instantly as it becomes available and the server wait for a client to request new data.How SignalR Works?
SignalR is an abstraction over some of the transports that are required to do real-time work between client and server. A SignalR connection starts as HTTP, and is then promoted to a WebSocket connection if it is available. WebSocket is the ideal transport for SignalR, since it makes the most efficient use of server memory, has the lowest latency, and has the most underlying features (such as full duplex communication between client and server), but it also has the most stringent requirements: WebSocket requires the server to be using Windows Server 2012 or Windows 8, and .NET Framework 4.5. If these requirements are not met, SignalR will attempt to use other transports to make its connections. SignalR is a technology that used a real-time work between client and server. It used WebSocket for a ideal transport, it makes the most efficient use of server memory. WebSocket has the full duplex communication between client and server. But WebSocket requires the server to be using Windows Server 2012 or Windows 8, and .NET Framework 4.5. SignalR connection starts as HTTP, and is then promoted to a WebSocket connection if it is available. If these requirements are not met, SignalR will attempt to use other transports to make its connections.Transports
Two types of transport:A) HTML 5 transports
i) WebSocket: If the both the server and browser indicate they can support Websocket. It supports latest versions of Microsoft Internet Explorer, Google Chrome, and Mozilla Firefox, and only has a partial implementation in other browsers such as Opera and Safari.
ii) Server Sent Events: Its known as EventSource. If the browser supports Server Sent Events, which is basically all browsers except Internet Explorer.
B) Comet transports
i) Forever Frame: It supports Internet Explorer only. Forever Frame creates a hidden IFrame which makes a request to an endpoint on the server that does not complete.
ii) Ajax long polling: Long polling does not create a persistent connection, but instead polls the server with a request that stays open until the server responds, at which point the connection closes, and a new connection is requested immediately.
Transport selection
i) If the browser is Internet Explorer 8 or earlier, Long Polling is used.ii) If the SignalR endpoint is not in the same domain as the hosting page, then WebSocket will be used if the following criteria are met:
a)The client supports CORS (Cross-Origin Resource Sharing).
b)The client supports WebSocket.
c)The server supports WebSocket.
iii)If any of these criteria are not met, Long Polling will be used.
iv)If JSONP is not configured and the connection is not cross-domain, WebSocket will be used if both the client and server support it.
v)If either the client or server do not support WebSocket, Server Sent Events is used if it is available.
vi)If Server Sent Events is not available, Forever Frame is attempted.
vii)If Forever Frame fails, Long Polling is used.
Create Project
Step-1: File > New > Project > ASP.NET Empty Web ApplicationStep-2: Create 4 table structure below:
CREATE TABLE [dbo].[ChatUserDetail]( [ID] [int] primary key IDENTITY(1,1) NOT NULL, [ConnectionId] [nvarchar](100) NULL, [UserName] [nvarchar](100) NULL, [EmailID] [nvarchar](50) NULL ) CREATE TABLE [dbo].[ChatMessageDetail]( [ID] [int] primary key IDENTITY(1,1) NOT NULL, [UserName] [nvarchar](100) NULL, [Message] [nvarchar](max) NULL, [EmailID] [nvarchar](50) NULL ) CREATE TABLE [dbo].[ChatPrivateMessageDetails]( [ID] [int] primary key IDENTITY(1,1) NOT NULL, [MasterEmailID] [nvarchar](50) NOT NULL, [ChatToEmailID] [nvarchar](50) NOT NULL, [Message] [nvarchar](max) NULL ) CREATE TABLE [dbo].[ChatPrivateMessageMaster]( [ID] [int] primary key IDENTITY(1,1) NOT NULL, [UserName] [nvarchar](100) NULL, [EmailID] [nvarchar](50) NULL )Step-3: In Solution Explorer, right-click the project, select Add > New Item > Visual C# > Data > ADO.NET Entity Data Model > Genetate from database > Next > New Connection > Enter "Server name" > Select "Log on to the server" > In the "Connect to a database" select database > OK > Select "Yes, include the sensitive data in the connection string" > Enter entity connection string name in the below textbox (Ex: Surajit_TestEntities) > Next > Select 4 tables > Finish
Step-4: Go to Tools > Library Package Manager > Package Manager Console and running a command: install-package Microsoft.AspNet.SignalR
Step-5: In Solution Explorer, right-click the project, select Add > SignalR Hub Class. Name the class ChatHub.cs
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Microsoft.AspNet.SignalR; namespace SignalRChat { public class ChatHub : Hub { public static string emailIDLoaded = ""; #region Connect public void Connect(string userName, string email) { emailIDLoaded = email; var id = Context.ConnectionId; using (Surajit_TestEntities dc = new Surajit_TestEntities()) { var item = dc.ChatUserDetails.FirstOrDefault(x => x.EmailID == email); if (item != null) { dc.ChatUserDetails.Remove(item); dc.SaveChanges(); // Disconnect Clients.All.onUserDisconnectedExisting(item.ConnectionId, item.UserName); } var Users = dc.ChatUserDetails.ToList(); if (Users.Where(x => x.EmailID == email).ToList().Count == 0) { var userdetails = new ChatUserDetail { ConnectionId = id, UserName = userName, EmailID = email }; dc.ChatUserDetails.Add(userdetails); dc.SaveChanges(); // send to caller var connectedUsers = dc.ChatUserDetails.ToList(); var CurrentMessage = dc.ChatMessageDetails.ToList(); Clients.Caller.onConnected(id, userName, connectedUsers, CurrentMessage); } // send to all except caller client Clients.AllExcept(id).onNewUserConnected(id, userName, email); } } #endregion #region Disconnect public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled) { using (Surajit_TestEntities dc = new Surajit_TestEntities()) { var item = dc.ChatUserDetails.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId); if (item != null) { dc.ChatUserDetails.Remove(item); dc.SaveChanges(); var id = Context.ConnectionId; Clients.All.onUserDisconnected(id, item.UserName); } } return base.OnDisconnected(stopCalled); } #endregion #region Send_To_All public void SendMessageToAll(string userName, string message) { // store last 100 messages in cache AddAllMessageinCache(userName, message); // Broad cast message Clients.All.messageReceived(userName, message); } #endregion #region Private_Messages public void SendPrivateMessage(string toUserId, string message, string status) { string fromUserId = Context.ConnectionId; using (Surajit_TestEntities dc = new Surajit_TestEntities()) { var toUser = dc.ChatUserDetails.FirstOrDefault(x => x.ConnectionId == toUserId); var fromUser = dc.ChatUserDetails.FirstOrDefault(x => x.ConnectionId == fromUserId); if (toUser != null && fromUser != null) { if (status == "Click") AddPrivateMessageinCache(fromUser.EmailID, toUser.EmailID, fromUser.UserName, message); // send to Clients.Client(toUserId).sendPrivateMessage(fromUserId, fromUser.UserName, message, fromUser.EmailID, toUser.EmailID, status, fromUserId); // send to caller user Clients.Caller.sendPrivateMessage(toUserId, fromUser.UserName, message, fromUser.EmailID, toUser.EmailID, status, fromUserId); } } } public ListStep-6: Create another class i.e. Startup.csGetPrivateMessage(string fromid, string toid, int take) { using (Surajit_TestEntities dc = new Surajit_TestEntities()) { List msg = new List (); var v = (from a in dc.ChatPrivateMessageMasters join b in dc.ChatPrivateMessageDetails on a.EmailID equals b.MasterEmailID into cc from c in cc where (c.MasterEmailID.Equals(fromid) && c.ChatToEmailID.Equals(toid)) || (c.MasterEmailID.Equals(toid) && c.ChatToEmailID.Equals(fromid)) orderby c.ID descending select new { UserName = a.UserName, Message = c.Message, ID = c.ID }).Take(take).ToList(); v = v.OrderBy(s => s.ID).ToList(); foreach (var a in v) { var res = new PrivateChatMessage() { userName = a.UserName, message = a.Message }; msg.Add(res); } return msg; } } private int takeCounter = 0; private int skipCounter = 0; public List GetScrollingChatData(string fromid, string toid, int start = 10, int length = 1) { takeCounter = (length * start); // 20 skipCounter = ((length - 1) * start); // 10 using (Surajit_TestEntities dc = new Surajit_TestEntities()) { List msg = new List (); var v = (from a in dc.ChatPrivateMessageMasters join b in dc.ChatPrivateMessageDetails on a.EmailID equals b.MasterEmailID into cc from c in cc where (c.MasterEmailID.Equals(fromid) && c.ChatToEmailID.Equals(toid)) || (c.MasterEmailID.Equals(toid) && c.ChatToEmailID.Equals(fromid)) orderby c.ID descending select new { UserName = a.UserName, Message = c.Message, ID = c.ID }).Take(takeCounter).Skip(skipCounter).ToList(); foreach (var a in v) { var res = new PrivateChatMessage() { userName = a.UserName, message = a.Message }; msg.Add(res); } return msg; } } #endregion #region Save_Cache private void AddAllMessageinCache(string userName, string message) { using (Surajit_TestEntities dc = new Surajit_TestEntities()) { var messageDetail = new ChatMessageDetail { UserName = userName, Message = message, EmailID = emailIDLoaded }; dc.ChatMessageDetails.Add(messageDetail); dc.SaveChanges(); } } private void AddPrivateMessageinCache(string fromEmail, string chatToEmail, string userName, string message) { using (Surajit_TestEntities dc = new Surajit_TestEntities()) { // Save master var master = dc.ChatPrivateMessageMasters.ToList().Where(a => a.EmailID.Equals(fromEmail)).ToList(); if (master.Count == 0) { var result = new ChatPrivateMessageMaster { EmailID = fromEmail, UserName = userName }; dc.ChatPrivateMessageMasters.Add(result); dc.SaveChanges(); } // Save details var resultDetails = new ChatPrivateMessageDetail { MasterEmailID = fromEmail, ChatToEmailID = chatToEmail, Message = message }; dc.ChatPrivateMessageDetails.Add(resultDetails); dc.SaveChanges(); } } #endregion } public class PrivateChatMessage { public string userName { get; set; } public string message { get; set; } } }
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(SignalRChat.Startup))] namespace SignalRChat { public class Startup { public void Configuration(IAppBuilder app) { // Any connection or hub wire up and configuration should go here app.MapSignalR(); } } }Step-7: After this create a index.html page.
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <link rel="stylesheet" href="/Css/ChatStyle.css" /> <link rel="stylesheet" href="/Css/JQueryUI/themes/base/jquery.ui.all.css" /> <!--Reference the jQuery library. --> <script src="/Scripts/jquery-1.8.2.min.js"></script> <script src="/Scripts/ui/jquery.ui.core.js"></script> <script src="/Scripts/ui/jquery.ui.widget.js"></script> <script src="/Scripts/ui/jquery.ui.mouse.js"></script> <script src="/Scripts/ui/jquery.ui.draggable.js"></script> <script src="/Scripts/ui/jquery.ui.resizable.js"></script> <!--Reference the SignalR library. --> <script src="/Scripts/jquery.signalR-2.2.0.js"></script> <!--Reference the autogenerated SignalR hub script. --> <script src="/signalr/hubs"></script> <script type="text/javascript"> $(function () { clearInterval(refreshId); setScreen(false); // Declare a proxy to reference the hub. var chatHub = $.connection.chatHub; $.connection.hub.logging = true; registerClientMethods(chatHub); // Start Hub $.connection.hub.start().done(function () { registerEvents(chatHub) }); }); // ------------------------------------------------------------------Variable ----------------------------------------------------------------------// var loadMesgCount = 10; var topPosition = 0; var refreshId = null; function scrollTop(ctrId) { var height = $('#' + ctrId).find('#divMessage')[0].scrollHeight; $('#' + ctrId).find('#divMessage').scrollTop(height); } // ------------------------------------------------------------------Start All Chat ----------------------------------------------------------------------// function setScreen(isLogin) { if (!isLogin) { $("#divChat").hide(); } else { $("#divChat").show(); } } function registerEvents(chatHub) { $("#btnStartChat").click(function () { var name = $("#txtNickName").val(); var email = $('#txtEmailId').val(); if (name.length > 0 && email.length > 0) { $('#hdEmailID').val(email); chatHub.server.connect(name, email); } else { alert("Please enter your details"); } }); $("#txtNickName").keypress(function (e) { if (e.which == 13) { $("#btnStartChat").click(); } }); $("#txtMessage").keypress(function (e) { if (e.which == 13) { $('#btnSendMsg').click(); } }); $('#btnSendMsg').click(function () { var msg = $("#txtMessage").val(); if (msg.length > 0) { var userName = $('#hdUserName').val(); chatHub.server.sendMessageToAll(userName, msg); $("#txtMessage").val(''); } }); } function registerClientMethods(chatHub) { // Calls when user successfully logged in chatHub.client.onConnected = function (id, userName, allUsers, messages) { setScreen(true); $('#hdId').val(id); $('#hdUserName').val(userName); $('#spanUser').html(userName); // Add All Users for (i = 0; i < allUsers.length; i++) { AddUser(chatHub, allUsers[i].ConnectionId, allUsers[i].UserName, allUsers[i].EmailID); } // Add Existing Messages for (i = 0; i < messages.length; i++) { AddMessage(messages[i].UserName, messages[i].Message); } $('.login').css('display', 'none'); } // On New User Connected chatHub.client.onNewUserConnected = function (id, name, email) { AddUser(chatHub, id, name, email); } // On User Disconnected chatHub.client.onUserDisconnected = function (id, userName) { $('#' + id).remove(); var ctrId = 'private_' + id; $('#' + ctrId).remove(); var disc = $('<div class="disconnect">"' + userName + '" logged off.</div>'); $(disc).hide(); $('#divusers').prepend(disc); $(disc).fadeIn(200).delay(2000).fadeOut(200); } // On User Disconnected Existing chatHub.client.onUserDisconnectedExisting = function (id, userName) { $('#' + id).remove(); var ctrId = 'private_' + id; $('#' + ctrId).remove(); } chatHub.client.messageReceived = function (userName, message) { AddMessage(userName, message); } chatHub.client.sendPrivateMessage = function (windowId, fromUserName, message, userEmail, email, status, fromUserId) { var ctrId = 'private_' + windowId; if (status == 'Click') { if ($('#' + ctrId).length == 0) { createPrivateChatWindow(chatHub, windowId, ctrId, fromUserName, userEmail, email); chatHub.server.getPrivateMessage(userEmail, email, loadMesgCount).done(function (msg) { for (i = 0; i < msg.length; i++) { $('#' + ctrId).find('#divMessage').append('<div class="message"><span class="userName">' + msg[i].userName + '</span>: ' + msg[i].message + '</div>'); // set scrollbar scrollTop(ctrId); } }); } else { $('#' + ctrId).find('#divMessage').append('<div class="message"><span class="userName">' + fromUserName + '</span>: ' + message + '</div>'); // set scrollbar scrollTop(ctrId); } } if (status == 'Type') { if (fromUserId == windowId) $('#' + ctrId).find('#msgTypeingName').text('typing...'); } else { $('#' + ctrId).find('#msgTypeingName').text(''); } } } // Add User function AddUser(chatHub, id, name, email) { var userId = $('#hdId').val(); var userEmail = $('#hdEmailID').val(); var code = ""; if (userEmail == email && $('.loginUser').length == 0) { code = $('<div class="loginUser">' + name + "</div>"); } else { code = $('<a id="' + id + '" class="user" >' + name + '<a>'); $(code).click(function () { var id = $(this).attr('id'); if (userEmail != email) { OpenPrivateChatWindow(chatHub, id, name, userEmail, email); } }); } $("#divusers").append(code); } // Add Message function AddMessage(userName, message) { $('#divChatWindow').append('<div class="message"><span class="userName">' + userName + '</span>: ' + message + '</div>'); var height = $('#divChatWindow')[0].scrollHeight; $('#divChatWindow').scrollTop(height); } // ------------------------------------------------------------------End All Chat ----------------------------------------------------------------------// // ------------------------------------------------------------------Start Private Chat ----------------------------------------------------------------------// function OpenPrivateChatWindow(chatHub, id, userName, userEmail, email) { var ctrId = 'private_' + id; if ($('#' + ctrId).length > 0) return; createPrivateChatWindow(chatHub, id, ctrId, userName, userEmail, email); chatHub.server.getPrivateMessage(userEmail, email, loadMesgCount).done(function (msg) { for (i = 0; i < msg.length; i++) { $('#' + ctrId).find('#divMessage').append('<div class="message"><span class="userName">' + msg[i].userName + '</span>: ' + msg[i].message + '</div>'); // set scrollbar scrollTop(ctrId); } }); } function createPrivateChatWindow(chatHub, userId, ctrId, userName, userEmail, email) { var div = '<div id="' + ctrId + '" class="ui-widget-content draggable" rel="0">' + '<div class="header">' + '<div style="float:right;">' + '<img id="imgDelete" style="cursor:pointer;" src="/Images/delete.png"/>' + '</div>' + '<span class="selText" rel="0">' + userName + '</span>' + '<span class="selText" id="msgTypeingName" rel="0"></span>' + '</div>' + '<div id="divMessage" class="messageArea">' + '</div>' + '<div class="buttonBar">' + '<input id="txtPrivateMessage" class="msgText" type="text" />' + '<input id="btnSendMessage" class="submitButton button" type="button" value="Send" />' + '</div>' + '<div id="scrollLength"></div>' + '</div>'; var $div = $(div); // ------------------------------------------------------------------ Scroll Load Data ----------------------------------------------------------------------// var scrollLength = 2; $div.find('.messageArea').scroll(function () { if ($(this).scrollTop() == 0) { if ($('#' + ctrId).find('#scrollLength').val() != '') { var c = parseInt($('#' + ctrId).find('#scrollLength').val(), 10); scrollLength = c + 1; } $('#' + ctrId).find('#scrollLength').val(scrollLength); var count = $('#' + ctrId).find('#scrollLength').val(); chatHub.server.getScrollingChatData(userEmail, email, loadMesgCount, count).done(function (msg) { for (i = 0; i < msg.length; i++) { var firstMsg = $('#' + ctrId).find('#divMessage').find('.message:first'); // Where the page is currently: var curOffset = firstMsg.offset().top - $('#' + ctrId).find('#divMessage').scrollTop(); // Prepend $('#' + ctrId).find('#divMessage').prepend('<div class="message"><span class="userName">' + msg[i].userName + '</span>: ' + msg[i].message + '</div>'); // Offset to previous first message minus original offset/scroll $('#' + ctrId).find('#divMessage').scrollTop(firstMsg.offset().top - curOffset); } }); } }); // DELETE BUTTON IMAGE $div.find('#imgDelete').click(function () { $('#' + ctrId).remove(); }); // Send Button event $div.find("#btnSendMessage").click(function () { $textBox = $div.find("#txtPrivateMessage"); var msg = $textBox.val(); if (msg.length > 0) { chatHub.server.sendPrivateMessage(userId, msg, 'Click'); $textBox.val(''); } }); // Text Box event $div.find("#txtPrivateMessage").keyup(function (e) { if (e.which == 13) { $div.find("#btnSendMessage").click(); } // Typing $textBox = $div.find("#txtPrivateMessage"); var msg = $textBox.val(); if (msg.length > 0) { chatHub.server.sendPrivateMessage(userId, msg, 'Type'); } else { chatHub.server.sendPrivateMessage(userId, msg, 'Empty'); } clearInterval(refreshId); checkTyping(chatHub, userId, msg, $div, 5000); }); AddDivToContainer($div); } function checkTyping(chatHub, userId, msg, $div, time) { refreshId = setInterval(function () { // Typing $textBox = $div.find("#txtPrivateMessage"); var msg = $textBox.val(); if (msg.length == 0) { chatHub.server.sendPrivateMessage(userId, msg, 'Empty'); } }, time); } function AddDivToContainer($div) { $('#divContainer').prepend($div); $div.draggable({ handle: ".header", stop: function () { } }); } // ------------------------------------------------------------------End Private Chat ----------------------------------------------------------------------// </script> </head> <body> <div id="header"> SignalR Chat Room </div> <br /> <br /> <br /> <div id="divContainer"> <div id="divLogin" class="login"> <div> Please Enter Your Name:<br /> <input id="txtNickName" type="text" class="textBox" /> </div> <div> Please Enter Your Email:<br /> <input id="txtEmailId" type="text" class="textBox" /> </div> <div id="divButton"> <input id="btnStartChat" type="button" class="submitButton" value="Start Chat" /> </div> </div> <div id="divChat" class="chatRoom"> <div class="title"> Welcome to Chat Room [<span id='spanUser'></span>] </div> <div class="content"> <div id="divChatWindow" class="chatWindow"> </div> <div id="divusers" class="users"> </div> </div> <div class="messageBar"> <input class="textbox" type="text" id="txtMessage" /> <input id="btnSendMsg" type="button" value="Send" class="submitButton" /> </div> </div> <input id="hdId" type="hidden" /> <input id="hdUserName" type="hidden" /> <input id="hdEmailID" type="hidden" /> </div> </body> </html>Step-8: Run the application
You see in the browser like below:
Now we need to enter the value like this:
After click on the button "Start chat" we see the screen like below:
Now copy url in the address bar ("http://localhost:53398/index.html") and open it in another browser and enter value in the same way. The sereen is below:
We can chat public and private chat like below:
0 comments