Wednesday, June 18, 2014

How to create simple chat application using SignalR 2.0 in Asp.net?

Today I will show you how to create simple chat application using SignalR. The tutorial demonstrates the following SignalR development tasks:

• Adding the SignalR library to an ASP.NET web application.

• Creating a hub class to push content to clients.

• Creating an OWIN startup class to configure the application.

• Using the SignalR jQuery library in a web page to send messages and display updates from the hub.

The following screen shot shows the chat application running in a browser.



Steps are following:

Step 1: Create a new project in .NET 4.5 “Asp.net Empty Web Application” like following.



Step 2: As I am using Visual Studio 2012, I have to manually run the following command to install “Microsoft.AspNet.SignalR” which will add necessary script files and assembly references to support SignalR.

install-package Microsoft.AspNet.SignalR


Go to “Tools” -> Library Package Manager -> Click on Package Manager Console

Choose default project to Your SimpleChat project and write “install-package Microsoft.AspNet.SignalR” in the console and press “Enter” to install. Console looks like following.



Now we need "json2.js". To install this file in our project follow THIS ARTICLE. This is necessary to work smoothly with SignalR application.

Step 3: Create “Users” folder in your project and Create User.cs file in it like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SimpleChat.Users
{
    public class User
    {
        public string Name { get; set; }
        public string Id { get; set; }
    }
}

Step 4. Create “UserRepository.cs” file in “Users” foler like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SimpleChat.Users
{
    public static class UserRepository
    {
        static List<User> lstUser = new List<User>();

        public static void add(User u)
        {
            lstUser.Add(u);
        }

        public static User getById(string id)
        {
            return lstUser.Where(usr => usr.Id == id).FirstOrDefault();

        }
        public static User getByName(string name)
        {
            return lstUser.Where(usr => usr.Name == name).FirstOrDefault();

        }
        public static List<User> getAll()
        {
            return lstUser;
        }
        public static void remove(User u)
        {
            lstUser.Remove(u);
        }
    }
}

Step 5. Create “ChatHub.cs” file in your project like this.
using System;
using System.Web;
using Microsoft.AspNet.SignalR;
namespace SimpleChat
{
    public class ChatHub : Hub
    {
        public void Send(string ToName, string message, string FromName)
        {
            //Check ToName, If ToName is specified, send message to that specified Name
            //If ToName is not specified, Send to All Users
            if (ToName != null)
            {
                //Get the ConnectionId of ToName
                string id = Users.UserRepository.getByName(ToName).Id;
                
                //Send message to specified User
                Clients.Client(id).broadcastMessage(FromName, message);

                //Check, if it is not self
                if (id != Context.ConnectionId.ToString())
                {
                    Clients.Client(Context.ConnectionId.ToString()).broadcastMessage("Me", message);
                }
            }
            else
            {
                //Send to all because no user selected.
                Clients.All.broadcastMessage(FromName, message);
            } 
        }

        //Add User in listview
        public void AddUser(string userName)
        {
            Users.User u = new Users.User();
            u.Id = Context.ConnectionId.ToString();
            u.Name = userName;
            Users.UserRepository.add(u);

            Clients.All.updateuserslist(userName);
        }

        //If user leaves the browser, remove from listview or from online users list.
        public override System.Threading.Tasks.Task OnDisconnected()
        {
            Users.User u = Users.UserRepository.getById(Context.ConnectionId.ToString());
            if (u != null)
            {
                RemoveUser(u.Name);
                Users.UserRepository.remove(u);

            }

            return base.OnDisconnected();
        }
        public void RemoveUser(string name)
        {
            Clients.All.updateuserslist_remove(name);
        }

    }
}
Step 6. Create “Startup.cs” file in your project like this.
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(SimpleChat.Startup))]
namespace SimpleChat
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Any connection or hub wire up and configuration should go here
            app.MapSignalR();
        }
    }
}

Step 7. Create “index.aspx” file in your project like this.
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>SignalR Simple Chat</title>
    <style type="text/css">
        .container {
            border: 0px solid #808080;
        }
    </style>

</head>
<body>

    <!--Script references. -->
    <!--Reference the jQuery library. -->
    <script src="Scripts/jquery-1.6.4.js"></script>
    <script src="Scripts/json2.js"></script>
    <!--Reference the SignalR library. -->
    <script src="Scripts/jquery.signalR-2.1.0.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="signalr/hubs"></script>
    <!--Add script to update the page and send messages.-->
    <script type="text/javascript">
        $(function () {
            // Declare a proxy to reference the hub. 
            var chat = $.connection.chatHub;
            // Create a function that the hub can call to broadcast messages.
            chat.client.broadcastMessage = function (name, message) {
                // Html encode display name and message. 
                var encodedName = $('<div />').text(name).html();
                var encodedMsg = $('<div />').text(message).html();
                // Add the message to the page. 
                $('#discussion').append('<li><strong>' + encodedName
                    + '</strong>:  ' + encodedMsg + '</li>');
            };

            //Update listview to add user
            chat.client.updateuserslist = function (name) {
                $('#ddlUsers').append(
                    $('<option></option>').val(name).html(name)
                );

            };

            //Update listview to remove user
            chat.client.updateuserslist_remove = function (name) {
                $('#ddlUsers option[value=' + name + ']').remove();

            };
             
            // Set initial focus to message input box.  
            $('#message').focus();
            // Start the connection.
            $.connection.hub.start().done(function () {
                $('#sendmessage').click(function () {
                    // Call the Send method on the hub. 
                    chat.server.send($('#ddlUsers').val(), $('#message').val(), $('#displayname').val());
                    // Clear text box and reset focus for next comment. 
                    $('#message').val('').focus();
                });
                $('#btnEnter').click(function () {
                    // Call the AddUser method on the hub. 
                    chat.server.addUser($('#displayname').val());
                    $('#btnEnter').hide();
                    $('#displayname').hide();
                    $('#FromName').text($('#displayname').val());
                });
            });
        });
    </script>
    <form id="form1" runat="server">
        <div>
            <asp:TextBox ID="displayname" runat="server"></asp:TextBox>

            <input type="button" id="btnEnter" value="Enter Your Name" />
            <br />
            <br />
             
            <table>
                <tr>
                    <td style="vertical-align: top;">Online Users:<br />
                        <asp:ListBox ID="ddlUsers" runat="server"></asp:ListBox>
                    </td>
                    <td style="border:solid 1px black;">
                        <div class="container" style="height: 330px; width: 300px;">
                            <ul id="discussion" style="overflow: auto; height: 280px; width: 250px;">
                            </ul>
                            <span id="FromName"></span>
                            <input type="text" id="message" />
                            <input type="button" id="sendmessage" value="Send" />

                        </div>
                    </td>
                </tr>
            </table>




        </div>
    </form>
</body>
</html>

Step 8. In code behind of “index.aspx” file, which is “index.aspx.cs” file like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace SimpleChat
{
    public partial class index : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {

                ddlUsers.DataSource = Users.UserRepository.getAll();
                ddlUsers.DataTextField = "Name";
                ddlUsers.DataValueField = "Name";
                ddlUsers.DataBind();


            }



        }


    }
}


That's it! you are ready to run it, BUT before you run your application, make sure that your referencing script files in index.aspx are matching with the project script files. sometimes .js files are updating their version frequently.

In our case, we are referencing following script files:
    <!--Script references. -->
    <!--Reference the jQuery library. -->
    <script src="Scripts/jquery-1.6.4.js"></script>
    <script src="Scripts/json2.js"></script>
    
    <!--Reference the SignalR library. -->
    <script src="Scripts/jquery.signalR-2.1.0.js"></script>
    <!--Reference the autogenerated SignalR hub script. -->
    <script src="signalr/hubs"></script>

And we have following script files in our project structure.


How it works:


1. Run the application.

2. It will ask you for your "Name".

3. Open another browser and paste the same URL. and again give some name.

4. You can see that all the names will be added in "Online Users" list.

5. Once some user will close the browser, User will be removed from the list automatically.

6. Now you can send message to anybody or to all.

7. To send message to all, don't select any user. and To send messsage to particular User, select it from Online Users list and start chating...like following

2 comments:

  1. Hey there! I just would like to offer you a big thumbs
    up for your great info you have got right here on this post.

    I am returning to your webbsite for more soon.

    ReplyDelete
  2. Howdy! I could have sworn I've been to this website befoore but
    after checking though some of the post I realized it's new to me.

    Anyhow, I'm definitely glad I found it and I'll be bookmarking and
    checking back frequently!

    ReplyDelete

React-select is very slow on larger list - Found solution - using react-window

 I had more than 4000 items in searchable dropdownlist. I have used react-select but it was very slow. finally I found complete solution to ...