2013-04-11

Hiding the ASPX markup when publishing an ASP.NET Web application

There are times that we need to hide the markup source from the published ASPX files. We have an option for that in the Visual Studio 2012 Update 2.

1) Right click on the web project from the solution explorer and choose Publish…

1

2) In the Publish Web dialog box, create a new profile (Or update an existing profile) and press Next > (Or choose the Connection tab). From there, choose your publish method (I’m using File System) and press Next >

2

3) In the Settings tab, expand the File Publish Options and tick Precompile during publishing.

3

4) Then click the Configure link next to Precompile during publishing option. It will open up a window shown as below. From there, un-tick Allow precompiled site to be updatable option and click OK.

4

5) Now you are done! Click Publish and it will publish the project. If you look in to the source code of ASPX, you will see the message “This is a marker file generated by the precompilation tool, and should not be deleted!”. But you can’t see the source code. If you look in to the bin folder of the published project, you will see additional files (Extension with .compiled) which are responsible for mapping the assembly code in to ASPX files.

For visual studio 2010 and Visual Studio 2012 (Without update), you will have to install the updates as describe in this link.

2013-04-01

How to make transparent elements without affecting the child elements

If we define the Opacity of an element with the usual CSS Opacity style, it will affect for the child elements too. It doesn’t matter whether you override the opacity in child element or not, it won’t change back. To get rid of that, we can use the below CSS3 style.

rgba(0, 0, 0, 0.4);

rgba is a CSS3 style. We can define the color using R G B values and as the final parameter, we can pass the opacity level. Then it will affect only for that element. See how cool and easy it is?

If you are worrying about the support of CSS3 in your browser, then you have two options.

1. Instead of making the elements as inner, you could always use position and margin styles to place the element on top of the other element. In that way, there are no child elements so won’t affect the opacity.

2. You can simply make images of the transparent elements and use them.

2013-03-31

Connecting a .NET client (Console application) to a website with SignalR

On one of my previous posts, I’ve shown you how to build a web based chat application with the use of SignalR. SignalR isn’t only restricted to web clients. It also works with many other clients like iOS, Android (There are no official support for them yet though. Those projects are community driven at this stage.) and Silverlight, .NET clients. In this blog post, I’m going to show you how to integrate a .NET client to my already built web application.

Following is the link to the web application I’ve created using SignalR

http://ruchirac.blogspot.com/2013/02/creating-chat-application-in-aspnet.html

Now I’m going to connect my .NET client (Console application) to that hosted website. For that, first of all I have to install SignalR .NET Client for my Console application. I can either do it by manually adding the DLL files and adding the references to the project or install it directly using NuGet Package manager. Since Installing it via NuGet Package manager is a lot easier, I’m going to use that.

.net client

After installing the Microsoft ASP.NET SignalR .NET Client, we are ready to develop our application. Following is the code for the Console app

using Microsoft.AspNet.SignalR.Client.Hubs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            var hubConnection = new HubConnection("
http://localhost:53748");
            var chat = hubConnection.CreateHubProxy("ChatHub");
            chat.On<string, string>("broadcastMessage", (name, message) => { Console.Write(name + ": "); Console.WriteLine(message); });
            hubConnection.Start().Wait();
            chat.Invoke("Notify", "Console app", hubConnection.ConnectionId);
            string msg = null;

            while ((msg = Console.ReadLine()) != null)
            {
                chat.Invoke("Send", "Console app", msg).Wait();
            }
        }
    }
}

At the first line, I’m connecting to the hosted website. In this example, the chat server. I’m using localhost because I’m using Visual Studio to run the application. If you’ve already hosted the application in somewhere else, then you have to give that web address to the HubConnection Constructor.

var hubConnection = new HubConnection("http://localhost:53748");

The above line will create a Connection to the Hub hosted in http://localhost:53748. We can use that to create a Hub Proxy. In my example, the hub name is ChatHub (The class name in server). So I’ve passed that to CreateHubProxy method. Then I’ve registered the method “braodcastMessage”, to display the messages on Console, app which I get from the other clients.

chat.On<string, string>("broadcastMessage", (name, message) => { Console.Write(name + ": "); Console.WriteLine(message); });

I’m getting two parameters from the server call, name and message. I’m writing them on the console as I get them. My server method looks like below

public void Send(string name, string message)
{
    // Call the broadcastMessage method to update clients.
    Clients.All.broadcastMessage(name, message);
}

As you can see, there I’m calling the method “broadcastMessage” on all clients. In the next line I’m starting the connection with the server.

hubConnection.Start().Wait();

I’m calling the Wait() method in order to wait till the connection made between server and my .NET client.

Next, I’m calling the Notify method in the server. It’s responsible for adding the connection ID to the client list and notifying other clients about the arrival of Console client.

chat.Invoke("Notify", "Console app", hubConnection.ConnectionId);

Here I’ve hardcoded the name “Console app”.

After that, I’m running a loop to get the messages from Console app. Then I invoke the server method as soon as I get a message from the .NET Client user. Then the server method, in this case “Send”, is responsible for broadcasting the message to all other connected clients.

string msg = null;

while ((msg = Console.ReadLine()) != null)
{
    chat.Invoke("Send", "Console app", msg).Wait();
}

So that’s all what it takes to build up a simple .NET client application which connects to a SignalR hub to do the real time communication. Following is a screenshot of how it looks like when it communicates with a web client.

SignalR console

2013-03-22

Crop an image when uploading to the server in ASP.NET

To crop an image when saving it to the server through asp:FileUpload control, we can use the below code. Here I’m using the Clone method of the Bitmap class and I’ve specified my area from the Rectangle. It actually creates a copy of the image within the specified area by the Rectangle.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;

namespace WebApplication1
{
    public partial class About : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            int x, y, width, height;
            x = y = 0; //X, Y values for crop the image.
            width = 300;
            height = 300;

            Rectangle cropArea = new Rectangle(x, y, width, height);

            Bitmap bmpImage = new Bitmap(FileUpload1.PostedFile.InputStream);
            Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
            bmpCrop.Save(@"D:\test.jpg");
        }
    }
}

Since we are using Rectangle and Bitmap classes, we have to import the System.Drawing namespace. Here I’m defining the width and height as 300px and X, Y value to 0. So it will crop 300x300 area from the image from the top left corner. Following is the markup I’ve used

<asp:FileUpload ID="FileUpload1" runat="server" />
<asp:Button ID="Button1" runat="server" Text="Button"
    onclick="Button1_Click" />

Following is an example image file I’ve uploaded:

1

After upload it and being cropped, following is the result file uploaded to the server.

test

Application_Error method Vs. Custom Error pages

I’m going to answer two FAQ about Application_Error method and Custom error pages.

1. If we have defined a custom error pages for our application, will the Application_Error method get fired?

Of course it will. Application_Error method in the Global.asax file will get fired whenever an unhandled exception occurs. Application_Error method will invoke every time an unhandled exception occurs regardless of whether you've declared a custom error page or not. After that method being executed, it will display the custom error page.

2. If we are doing a Response.Redirect or Server.Transfer inside the Application_Error method, then what will happen? Will the custom error page get displayed after that?

No it will not. Then the application will be redirected to the page which we've defined in the Application_Error method. It will not go to the custom error page since we are overriding the redirect page in global.asax.

Restrict user access to a website based on IP address

Though the method I’m going to describe below would not work 100%, it is the closest thing you can do within few minutes.

First, you may need to keep track of the suspected IP list in a database table or in some other storage. At the Application_BeginRequest method of the Global.asax file, iterate through each IP and match it with the current user’s IP. If it matches, then redirect the user to a permission denied page.

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string ip = HttpContext.Current.Request.UserHostAddress;

    if(ip == suspectedIP){
        Response.Redirect("~/PermissionDenied.aspx");
    }
}

2013-03-12

Logging with ASP.NET - Part 2 (Using an XML file as the configuration file and logging levels)

Here I've shown how to use an XML file as the log4net configuration file and how to use logging levels in log4net to manage our log info efficiently into log files. Also, I've shown how the RollingFileAppender works and how to give a dynamic name to the log file (ex:-Date) I'm using Visual Studio 2012 and C#.NET to do the demonstration.

If the text isn’t clear, please use the HD format and full screen mode.

2013-02-26

Basics of creating a multiplayer web based game with jQuery and SignalR

In this article, I’m going to show how to use jQuery to move an object on web page and how we can use SignalR to notify all the connected clients about the movement and replicate that movement on each client.

The basic rule of a multiplayer web based game is, you have to reflect the changes done in a one player machine on other players machines, real-time. The challenge is how you are going to do this in real time. If you are using some polling mechanism, then some movements will get missed or slower to replicate in other players machine. Use with SignalR, multiplayer web based games are much easier to develop.

Let’s have a look at how to accomplish the basic rules of a multiplayer game, i.e. reflecting the changes real time in other clients, in an ASP.NET application with the help of SignalR.

Before we begin, following is a screen shot of the sample application. As you can see, I’m running the same application on two different browsers and I’m expecting the same movement of Scooby on both web pages without browser refresh.

Untitled

First of all, we have to add the reference to SignalR client and server libraries. Easiest way to do this is by NuGet packages. Right click on your project and click on Manage NuGet Packages…. Then type SignalR on the search box and click Install. Now you have SignalR in your application. I’m going to use some animation in my game, so let’s also install the jQuery UI from NuGet Packages.

Now we are ready to develop our application.

First, I’m going to add the Hub routing in my Global.asax file as shown below

protected void Application_Start(object sender, EventArgs e)
{
    RouteTable.Routes.MapHubs();
}

Then, I’m going to add the page where I’m going to develop the game. In there, I’m referencing to the jQuery latest version, jQuery UI library, SignalR client library. SignalR Hubs which will dynamically be created on the fly.

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js" charset="utf-8">
</script>
<script src="Scripts/jquery-ui-1.10.0.js"></script>
<script src="Scripts/jquery.signalR-1.0.0.js"></script>
<script src="/signalr/hubs"></script>

Next I’m going to develop my game using the jQuery/JavaScripts. Following is the code for that

<script type="text/javascript">
       $(function () {
           var moveScooby = $.connection.moveScoobyHub;

           moveScooby.client.runScoobyForward = function () {
               $("#scooby").animate({
                   marginLeft: '+=1'
               }, 0);
           }

           moveScooby.client.runScoobyBackward = function () {
               $("#scooby").animate({
                   marginLeft: '-=1'
               }, 0);
           }

           moveScooby.client.runScoobyUpward = function () {
               $("#scooby").animate({
                   marginTop: '-=30'
               }, 500, 'easeOutCubic', function () {
                   $("#scooby").animate({
                       marginTop: '+=30'
                   }, 500, 'easeInExpo');
               });
           }

           $.connection.hub.start().done(function () {
               $(document).keydown(function (e) {
                   var audio = document.getElementById("snd");
                   switch (e.which) {
                       case 32:
                           $("#scooby").animate({
                               marginTop: '-=30'
                           }, 500, 'easeOutCubic', function () {
                               $("#scooby").animate({
                                   marginTop: '+=30'
                               }, 500, 'easeInExpo');
                           });
                           moveScooby.server.moveScoobyUpward();
                           break;
                       case 37:
                           $("#scooby").animate({
                               marginLeft: '-=1'
                           }, 0);
                           moveScooby.server.moveScoobyBackward();
                           break;
                       case 39:
                           $("#scooby").animate({
                               marginLeft: '+=1'
                           }, 0);
                           moveScooby.server.moveScoobyForward();
                           break;
                   }
               });
           }
           );
       });
   </script>

Here, I will be using a Scooby-doo image and I will move it on the web page as we press arrow keys. Scooby will jump when you press the space bar.

My hub class name is MoveScoobyHub.cs. In SignalR, we must use lower case camel notation in order to access the server properties/methods. So I access my hub like below

var moveScooby = $.connection.moveScoobyHub;

Note the “m” in “moveScoobyHub” is simple even though the class name has capital “M”.

Next I’ve declared 3 methods to move the Scooby on all the client machines.

moveScooby.client.runScoobyForward = function () {
    $("#scooby").animate({
        marginLeft: '+=1'
    }, 0);
}

moveScooby.client.runScoobyBackward = function () {
    $("#scooby").animate({
        marginLeft: '-=1'
    }, 0);
}

moveScooby.client.runScoobyUpward = function () {
    $("#scooby").animate({
        marginTop: '-=30'
    }, 500, 'easeOutCubic', function () {
        $("#scooby").animate({
            marginTop: '+=30'
        }, 500, 'easeInExpo');
    });
}

First method will take care of moving the Scooby forward. It will add 1 unit to the margin left of the scooby object. I’m using jQuery animate() method to add the motion to the object. To make the movement to a normal speed, I’m setting the duration of the animation to 0. You can make the movement slow by increasing the duration. Same as in runScoobyForward function, I’ve written the runScoobyBackward function to move the Scooby backward. There I’m deducting a one unit from the left margin so the object will move backward.

Third method is for make the Scooby jump. I’m setting the top margin of the scooby object to –30px so the object will move upwards. To make the jumping looks real, I’m adding easeOutCubic to the animation. Once the animation is done, I’m calling the animate() method once again to move the Scooby to the ground (He can’t jump and stay forever in the air!). To do that, I’m adding 30px for the scooby object and I’m using easeInExpo for the animation so it looks more realistic with the gravity effect. So now the Scooby will back in the ground (-30px + 30px = 0)

Now those are the three methods I’m using to to do the movement of Scooby.

$.connection.hub.start().done(function () {
    $(document).keydown(function (e) {
        switch (e.which) {
            case 32:
                moveScooby.server.moveScoobyUpward();
                break;
            case 37:
                moveScooby.server.moveScoobyBackward();
                break;
            case 39:
                moveScooby.server.moveScoobyForward();
                break;
        }
    });
}
);

Once the connection to hub starts, I’m adding a function to keydown event of the web page. In that function I’m getting the keycode of the key pressed. If it’s the space bar (keycode=32), I’m calling the moveScoobyUpward method in the server. It looks like below

public void moveScoobyUpward()
{
    Clients.All.runScoobyUpward();
}

As you can see, it will in return call the runScoobyUpward() function on all the clients.

If it’s the left arrow (keycode=37), I’m calling the moveScoobyBackward method in the server. It looks like below

public void moveScoobyBackward()
{
    Clients.All.runScoobyBackward();
}

As you can see, it will in return call the runScoobyBackward() function on all the clients.

If it’s the right arrow (keycode=39), I’m calling the moveScoobyForward method in the server. It looks like below

public void moveScoobyForward()
{
    Clients.All.runScoobyForward();
}

As you can see, it will in return call the runScoobyForward() function on all the clients.

So that’s it! As for my markup, I’m simply using an image inside a div. I’ve set a background image for the div.

<body>
    <div style="background-image: url('Images/scooby01.jpg'); background-repeat: no-repeat; height: 438px; width: 584px">
        <img src="Images/aniscooby.gif" id="scooby" width="100" height="100" style="margin-top: 340px;" />
    </div>
</body>

Altogether, following is the complete aspx page markup. Of course there are no code behind code for that. You can surely copy paste this to a simple HTML page and it will work.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UI.aspx.cs" Inherits="SignalRUIChange.UI" %>

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript"
        src="
http://code.jquery.com/jquery-latest.js" charset="utf-8">
    </script>
    <script src="Scripts/jquery-ui-1.10.0.js"></script>
    <script src="Scripts/jquery.signalR-1.0.0.js"></script>
    <script src="/signalr/hubs"></script>
    <script type="text/javascript">
        $(function () {
            var moveScooby = $.connection.moveScoobyHub;

            moveScooby.client.runScoobyForward = function () {
                $("#scooby").animate({
                    marginLeft: '+=1'
                }, 0);
            }

            moveScooby.client.runScoobyBackward = function () {
                $("#scooby").animate({
                    marginLeft: '-=1'
                }, 0);
            }

            moveScooby.client.runScoobyUpward = function () {
                $("#scooby").animate({
                    marginTop: '-=30'
                }, 500, 'easeOutCubic', function () {
                    $("#scooby").animate({
                        marginTop: '+=30'
                    }, 500, 'easeInExpo');
                });
            }

            $.connection.hub.start().done(function () {
                $(document).keydown(function (e) {
                    switch (e.which) {
                        case 32:
                            moveScooby.server.moveScoobyUpward();
                            break;
                        case 37:
                            moveScooby.server.moveScoobyBackward();
                            break;
                        case 39:
                            moveScooby.server.moveScoobyForward();
                            break;
                    }
                });
            }
            );
        });
    </script>
</head>
<body>
    <div style="background-image: url('Images/scooby01.jpg'); background-repeat: no-repeat; height: 438px; width: 584px">
        <img src="Images/aniscooby.gif" id="scooby" width="100" height="100" style="margin-top: 340px;" />
    </div>
</body>
</html>

And following is the server side code for the Hub. Note that I’m inheriting it from the SignalR Hub class in order to make it a hub.

using Microsoft.AspNet.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace SignalRUIChange
{
    public class MoveScoobyHub: Hub
    {
        public void moveScoobyForward()
        {
            Clients.All.runScoobyForward();
        }

        public void moveScoobyBackward()
        {
            Clients.All.runScoobyBackward();
        }

        public void moveScoobyUpward()
        {
            Clients.All.runScoobyUpward();
        }
    }
}

2013-02-18

Logging with ASP.NET - Part 1 (Configuring log4net)

Here I've shown how to do basic logging with an ASP.NET application. I've used log4net logging provider for that. I'm using Visual Studio 2012 and C#.NET to do the demonstration.

Here is the first part of a video tutorial series I’m hoping to do in log4net. If the text isn’t clear in the demo, please use the HD format and full screen mode.

2013-02-11

Creating a chat application in ASP.NET with SignalR

There are many things we can do with SignalR. It’s never been this easier to build real time web applications. In this post, I’m going to show how to build a chat application and add some additional functionality to it.

First of all, we have to get the SignalR library and include it in our ASP.NET web application. Easiest way to do this is by going to NuGet package manager and install it from there. You can go to the NuGet package manager in Project – > Manage NuGet Packages…

After you install it, you can see there are new script files in the Script folder as well as some new references. Scripts are for the SignalR client library and references are there for SignalR server library.

Now we are ready to develop our application with SignalR.

Let’s start by building the web page. Following is the body section of my HTML page. Note that I’m using a simple HTML page as my chat page.

<body style="border: solid gray; height: 90%;">
    <input type="hidden" id="displayname" />
    <div style="height: 80%;">
        <div id="chats" style="width: 80%; float: left;"></div>
        <div id="onlineList" style="width: 19%; float: right; border-left: solid red 2px; height: 100%;">
            <div style="font-size: 20px; border-bottom: double">Online Users</div>
        </div>
    </div>
    <div style="height: 19%; border-top: double black; background-color: lightgray">
        <div style="float: left; height: 90%; top: 10%; position: relative;">
            <textarea spellcheck="true" id="message" style="width: 625px; height: 80%"></textarea>
        </div>
        <div style="position: relative; top: 30%; float: left;">
            <input type="button" id="sendmessage" value="Send" />
        </div>
        <div style="position: relative; top: 30%; float: left;">
            <select id="users">
                <option value="All">All</option>
            </select>
        </div>
    </div>
</body>

I’m using a hidden field to store the username. A div called ‘chats’ to display the chat messages. A div called ‘onlineList’ to display the online users. At the bottom, I’ve placed the text area along with the send button. Also, I’ve included a dropdown list to display the online users so the user can select to whom (s)he is going to send the message or (s)he can simply select ‘All’ option to send the message to all users.

So that’s the layout of my webpage. Now let’s look at the head section of it.

<head>
    <style>
        .border {
            border-bottom: solid gray 1px;
        }

        .smileys {
            height: 15px;
        }
    </style>

    <title>Chat demo in ASP.NET using SignalR</title>

    <script src="Scripts/jquery-1.6.4.min.js"></script>

    <script src="Scripts/jquery.signalR-1.0.0-rc2.js"></script>

    <!--Reference the autogenerated SignalR hub script. -->
    <script src="/signalr/hubs"></script>

    <script type="text/javascript">
        $(function () {

            var chat = $.connection.chatHub;

            // Get the user name.
            $('#displayname').val(prompt('Enter your name:', ''));

            chat.client.differentName = function (name) {
                // Prompts for different user name
                $('#displayname').val(prompt('Please enter different username:', ''));
                chat.server.notify($('#displayname').val(), $.connection.hub.id);
            };

            chat.client.online = function (name) {
                // Update list of users
                if (name == $('#displayname').val())
                    $('#onlineList').append('<div class="border" style="color:red">You: ' + name + '</div>');
                else {
                    $('#onlineList').append('<div class="border">' + name + '</div>');
                    $("#users").append('<option value="' + name + '">' + name + '</option>');
                }
            };

            chat.client.enters = function (name) {
                $('#chats').append('<div class="border"><i>' + name + ' enters chatroom</i></div>');
                $("#users").append('<option value="' + name + '">' + name + '</option>');
                $('#onlineList').append('<div class="border">' + name + '</div>');
            };

            // Create a function that the hub can call to broadcast chat messages.
            chat.client.broadcastMessage = function (name, message) {
                //Interpret smileys
                message = message.replace(":)", "<img src=\"/emoticons/smile.png\" class=\"smileys\" />");
                message = message.replace(";)", "<img src=\"/emoticons/wink.png\" class=\"smileys\" />");
                message = message.replace(":D", "<img src=\"/emoticons/laugh.png\" class=\"smileys\" />");

                //display the message
                $('#chats').append('<div class="border"><span style="color:blue">' + name + '</span>: ' + message + '</div>');
            };

            chat.client.disconnected = function (name) {
                //Calls when someone leaves the page
                $('#chats').append('<div class="border"><i>' + name + ' leaves chatroom</i></div>');
                $('#onlineList div').remove(":contains('" + name + "')");
                $("#users option").remove(":contains('" + name + "')");
            }

            // Start the connection.
            $.connection.hub.start().done(function () {
                //Calls the notify method of the server
                chat.server.notify($('#displayname').val(), $.connection.hub.id);

                $('#sendmessage').click(function () {
                    if ($("#users").val() == "All") {
                        // Call the Send method on the hub.
                        chat.server.send($('#displayname').val(), $('#message').val());
                    }
                    else {
                        chat.server.sendToSpecific($('#displayname').val(), $('#message').val(), $("#users").val());
                    }
                    // Clear text box and reset focus for next comment.
                    $('#message').val('').focus();
                });

            });
        });
    </script>
</head>

At the head section of the HTML file, I’ve added styles, references to the jQuery library, SignalR library and auto generated SignalR hub script. Next I’ve included the client side functions which are responsible for displaying chats, notify when a user enters or leaves the chat room, sending the chats and maintaining up to date online users list.

Following is the whole code behind responsible for handling the client side events. I have written it in a CS files called ChatHub.cs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace SingalRTest
{
    public class ChatHub : Hub
    {
        static ConcurrentDictionary<string, string> dic = new ConcurrentDictionary<string, string>();

        public void Send(string name, string message)
        {
            // Call the broadcastMessage method to update clients.
            Clients.All.broadcastMessage(name, message);
        }

        public void sendToSpecific(string name, string message, string to)
        {
            // Call the broadcastMessage method to update clients.
            Clients.Caller.broadcastMessage(name, message);
            Clients.Client(dic[to]).broadcastMessage(name, message);
        }

        public void Notify(string name, string id)
        {
            if (dic.ContainsKey(name))
            {
                Clients.Caller.differentName();
            }
            else
            {
                dic.TryAdd(name, id);

                foreach (KeyValuePair<String, String> entry in dic)
                {
                    Clients.Caller.online(entry.Key);
                }

                Clients.Others.enters(name);
            }
        }

        public override Task OnDisconnected()
        {
            var name = dic.FirstOrDefault(x => x.Value == Context.ConnectionId.ToString());
            string s;
            dic.TryRemove(name.Key, out s);
            return Clients.All.disconnected(name.Key);
        }
    }
}

Now let’s have a look at both the client side events and server side events. First, I’m referencing to my server hub using the below code in client side

var chat = $.connection.chatHub;

Note that I’m using the same name as the class name to refer to the hub. My class, ChatHub is inherited from the SignalR Hub class.

Then I’m prompting the user for a username and I’m storing the username in the ‘displayname’ hidden field. That’s what the below code do

            $('#displayname').val(prompt('Enter your name:', ''));

In code behind, I’m using a concurrent static Dictionary to maintain the online users lists.

static ConcurrentDictionary<string, string> dic = new ConcurrentDictionary<string, string>();

Whenever a user enters the chat room, I’m adding the username as the key and connection ID as the value to that dictionary. That’s what the below server side method do

        public void Notify(string name, string id)
        {
            if (dic.ContainsKey(name))
            {
                Clients.Caller.differentName();
            }
            else
            {
                dic.TryAdd(name, id);

                foreach (KeyValuePair<String, String> entry in dic)
                {
                    Clients.Caller.online(entry.Key);
                }

                Clients.Others.enters(name);
            }
        }

As you can see, I’m passing two parameters, name and id.

As soon as the connection made with the server, I’m calling that method.

$.connection.hub.start().done(function () {
    //Calls the notify method of the server
    chat.server.notify($('#displayname').val(), $.connection.hub.id);
.............................................……………………………………..

As you can see from the above code, I’m passing the username I’ve stored in the hidden field and I’m passing the unique ID which was generated when the connection has been made with the server.

If the Dictionary already contains the username entered, I’m calling the method diiferentName for the Caller. Note that I’m calling that method ONLY to the calling client. That’s why I’ve used Client.Caller. So now, it will call the differentName method in the client side for the Caller Client. Following is the differentName method in my client side script.

chat.client.differentName = function (name) {
    // Prompts for different user name
    $('#displayname').val(prompt('Please enter different username:', ''));
    chat.server.notify($('#displayname').val(), $.connection.hub.id);
};

As you can see, I’m prompting again for a different username. Then I’m again calling the Notify method in the server by passing the new username and connection ID.

If there is no user by that name, then it will add the username to the Dictionary.

dic.TryAdd(name, id);

Then I have to display the online list to the just entered client. For that, I’m calling the online method for the Caller Client. Note that, online client function will only get called for the calling client, not for all the clients.

foreach (KeyValuePair<String, String> entry in dic)
{
    Clients.Caller.online(entry.Key);
}

For each user in the list, I’m calling the online function. Below is that function

chat.client.online = function (name) {
    // Update list of users
    if (name == $('#displayname').val())
        $('#onlineList').append('<div class="border" style="color:red">You: ' + name + '</div>');
    else {
        $('#onlineList').append('<div class="border">' + name + '</div>');
        $("#users").append('<option value="' + name + '">' + name + '</option>');
    }
};

As you can see, if the name equals to the caller client, I’m adding a You: in front of the name and it will get displayed in red color. Otherwise I’m just appending the usernames to the onlineList div and adding an option to the dropdown list.

For the rest of the clients, I’m notifying that a new user enters the chat room. For that, I’m using the below code

Clients.Others.enters(name);

Note that I’m using Clients.Others, which will display the message to all the connected clients except the caller (There is no point of notifying the caller that (s)he just entered to the chat room). So I am calling the enters method in the client side and I’m passing the username so I can notify others who has just entered to the chat room. Following is the enters function.

chat.client.enters = function (name) {
    $('#chats').append('<div class="border"><i>' + name + ' enters chatroom</i></div>');
    $("#users").append('<option value="' + name + '">' + name + '</option>');
    $('#onlineList').append('<div class="border">' + name + '</div>');
};

As you can see, I’m showing username enters chatroom in the chats div. For rest of the clients, I have to update the online users list too. So I’m going to do that in the enters method by appending the new user name to the onlineList div and adding a new option to the users dropdown list.

Now that’s what happened when a client made a connection with the server, in this example, when the user joins the chat room. Now let’s see how to send the chat messages to users. For that, I’ve bound the below client side function to the Send button.

$('#sendmessage').click(function () {
    if ($("#users").val() == "All") {
        // Call the Send method on the hub.
        chat.server.send($('#displayname').val(), $('#message').val());
    }
    else {
        chat.server.sendToSpecific($('#displayname').val(), $('#message').val(), $("#users").val());
    }
    // Clear text box and reset focus for next comment.
    $('#message').val('').focus();
});

In the dropdown list, if the user has selected “All” option, then I’m calling the Send method in the server. I’m passing the username along with the text in the message textarea. Following is the send method in the server

public void Send(string name, string message)
{
    // Call the broadcastMessage method to update clients.
    Clients.All.broadcastMessage(name, message);
}

It will accept the two parameters and it will call the broadcastMessage function for all the clients. Since the user has selected “All” option in the dropdown list, now it will send the message to all the connected clients. The broadcastMessage function will get called for all the clients.

chat.client.broadcastMessage = function (name, message) {
    //Interpret smileys
    message = message.replace(":)", "<img src=\"/emoticons/smile.png\" class=\"smileys\" />");
    message = message.replace(";)", "<img src=\"/emoticons/wink.png\" class=\"smileys\" />");
    message = message.replace(":D", "<img src=\"/emoticons/laugh.png\" class=\"smileys\" />");

    //display the message
    $('#chats').append('<div class="border"><span style="color:blue">' + name + '</span>: ' + message + '</div>');
};

As you can see, it will accept the two parameters which were passed from the server. First it will check for the smiley syntaxes in the message and replace those with emoticons. Smile

After building the final message with the images, I’m appending it to the chats div along with the username. Now all the clients will get the message with the username!

Now let’s move on to the part where a user can send messages only to specific user (not all the clients). For that I’m calling the sendToSpecific server side method. As you can see from the Send button event, if the value selected in the dropdown list is not “All”, I’m calling the sendToSpecific method by passing the caller name, message and the callee name (The selected value in the dropdown list). My sendToSpecific method looks like below

public void sendToSpecific(string name, string message, string to)
{
    // Call the broadcastMessage method to update clients.
    Clients.Caller.broadcastMessage(name, message);
    Clients.Client(dic[to]).broadcastMessage(name, message);
}

Since now I need to display the message only between two users, I’m calling the Clients.Caller.broadcastMessage and Clients.Client(dic[to]).broadcastMessage. By calling the Clients.Caller.broadcastMessage, I’m displaying the message to the caller. By calling the below line, I’m displaying the message ONLY to the particular client. That’s why I’m passing the connection ID of that client to the Client method.

Clients.Client(dic[to]).broadcastMessage(name, message);

I’m passing the callee name to the Dictionary so it will return the connection ID associated for that username. Now it will broadcast the message only to that specific client.

So that’s how we can broadcast messages between two specific clients. Now let’s move to the final part, what will happen when a user leaves the chat room? Pretty simple, I will need to remove that username from the online user lists and from the dropdown list in client side and I will need to remove the particular dictionary entry associated for that user from the server side. Let’s see how to do that.

There is a server side method in the SignalR library, called OnDisconnected(), which will get called whenever the connection get closed from a client. So we can handily use that for our purpose here.

public override Task OnDisconnected()
{
    var name = dic.FirstOrDefault(x => x.Value == Context.ConnectionId.ToString());
    string s;
    dic.TryRemove(name.Key, out s);
    return Clients.All.disconnected(name.Key);
}

As you can see, first I’m removing the entry in the dictionary associated with that username. Then I’m calling the disconnected client side function for all the clients.

chat.client.disconnected = function (name) {
    //Calls when someone leaves the page
    $('#chats').append('<div class="border"><i>' + name + ' leaves chatroom</i></div>');
    $('#onlineList div').remove(":contains('" + name + "')");
    $("#users option").remove(":contains('" + name + "')");
}

From the disconnected function, I’m simply notifying all the clients that particular user leaves the chat and then remove his/her name from both the online list and dropdown list.

Well, that’s how we can simply create a chat application in ASP.NET with SignalR. SmileFollowing are some screenshots of running application

Untitled

leaves

Real Time Analytics