Click here to Skip to main content
13,259,539 members (53,581 online)
Click here to Skip to main content
Add your own
alternative version

Stats

25.6K views
1.4K downloads
57 bookmarked
Posted 19 Sep 2015

SignalR - Message Watch Application in C# with Database Notifications

, 19 Sep 2015
Rate this:
Please Sign up or sign in to vote.
Signal R Message Logging Application

Introduction

SignalR is a library which provide the process of adding real-time updates in web application. In Real-time web functionality Server automatically sends response to connected clients rather than having the server wait for a client to request new data.

Background

Message Watch is a web application which takes data from a database and updates data in real time to clients.In this web app, Different application logs message in a database and through database notification and SignalR we will update those messages to users at real time.

Using the code

I would like to start with the database(In Step 1 and Step 2) and then we will jump to our C# code.

Step 1 (Set up Database) : Create a database named SignalRDatabase and Create below tables

a. Application

b. logLevel

c. MessageLog

d. OperationCode

Set Enable Broker flag to true as below 

Step 2 (Set up Application) : Open Visual Studio(I am using Visual Studio 2013) and Then Click on Web and then select Asp.net web application and then Select MVC(give a name to application(MessageWatch in my case))

Right Click on your application and Select ManageNuGet Packages and Search SignalR in Online Section and select Microsoft Asp.net SignalR as below

 

After installation, check Reference folder, There will be some references related to SignalR.

Step 3 (Its Code Time) : 

Go to Startup.cs and Map SignalR as below

using Microsoft.Owin;
using Owin;

[assembly: OwinStartupAttribute(typeof(MessageWatch.Startup))]
namespace MessageWatch
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

Create a class named MessageLog.cs (Add all the properties which you want to update to clients)

public class MessageLog
{
    public string Name { get; set; }

    public int EventID { get; set; }

    public string LogLevelName { get; set; }

    public string OperationCodeName { get; set; }

    public string ServerName { get; set; }

    public string ComponentName { get; set; }

    public string SubComponentName { get; set; }
}

 

Right Click on the solution and add a SignalR Hub Class(NotificationHub.cs in my case) as below. Responsibility of this function is to send updates to clients.

Add a method named GetAllMessagesLog() in NotificatiobHub.cs. It will pull all the required information from the database and will call send() function.

In This function we are setting up database dependency and fetching all the records from the database

public IEnumerable<MessageLog> GetAllMessagesLog()
   {
       string conStr = ConfigurationManager.ConnectionStrings["SignalRDB"].ConnectionString;
       SqlConnection connection = new SqlConnection(conStr);

       string query = "SELECT Message,EventID,LL.Name as LogLevelID,OC.Name as OperationCodeID,ML.ServerName,ML.ComponentName,ML.SubComponentName FROM [dbo].[MessageLog] ML inner join [dbo].[LogLevel] LL on ML.LogLevelID = LL.ID inner join [dbo].[OperationCode] OC on ML.OperationCodeID = OC.ID";
       SqlDependency.Start(conStr);
       SqlCommand command = new SqlCommand(query, connection);
       SqlDependency dependency = new SqlDependency(command);

       //If Something will change in database and it will call dependency_OnChange method.
       dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
       connection.Open();
       SqlDataAdapter da = new SqlDataAdapter(command);
       DataTable dt = new DataTable();
       da.Fill(dt);

       List<MessageLog> messageList = new List<MessageLog>();
       for (int i = 0; i < dt.Rows.Count; i++)
       {
           MessageLog ml = new MessageLog();
           ml.Name = dt.Rows[i]["Message"].ToString();
           ml.EventID = Convert.ToInt32(dt.Rows[i]["EventID"].ToString());
           ml.LogLevelName = dt.Rows[i]["LogLevelID"].ToString();
           ml.OperationCodeName = dt.Rows[i]["OperationCodeID"].ToString();
           ml.ServerName = dt.Rows[i]["ServerName"].ToString();
           ml.ComponentName = dt.Rows[i]["ComponentName"].ToString();
           ml.SubComponentName = dt.Rows[i]["SubComponentName"].ToString();
           messageList.Add(ml);
       }
       return messageList;

   }

Add Two more methods which will get called when something will change in database.

private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
   {
       if (e.Type == SqlNotificationType.Change)
       {

           SendNotifications();
       }
   }
   private void SendNotifications()
   {
       IEnumerable<MessageLog> messageList = GetAllMessagesLog();

       IHubContext context = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
       context.Clients.All.broadcastMessage(messageList);//Will update all the clients with message log.

   }

Go to Controller Folder and open Home Controller and add a action method as below

public ActionResult GetNotification()
    {
        return View();
    }

Create a Empty view as below

Open newly creted view GetNotification.cshtml and add some Css in head section

<style type="text/css">.container {
            background-color: #99CCFF;
            border: thick solid #808080;
            padding: 20px;
            margin: 20px;
        }</style>
<style type="text/css">
body {
       font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
       font-size: 16px;
        
     }

#messageTable table {
            border-collapse: collapse;
                    }

#messageTable table th, #messageTable table td {
                padding: 2px 6px;
            }

#messageTable table td {
                text-align: right;
            }

#messageTable .loading td {
            text-align: left;
        }
</style>

Add SignalR Scripts in GetNotification.cshtml Page

 var ew = $.connection.notificationHub;
            //This method will fill all the Messages in case of any database change.
            //Server side code will call this function to update information client.
            ew.client.broadcastMessage = function (messageLogs) {
                // Html encode display name and message.
                var i = 0;
                if ($('#hdnValue').val() == 1) {
                    $messageTableBody.empty();

                    $.each(messageLogs, function () {
                        var encodedName = messageLogs[i].Name;
                        var encodedEvent = messageLogs[i].EventID;
                        var encodedLogLevel = messageLogs[i].LogLevelName;
                        var encodedOCode = messageLogs[i].OperationCodeName;
                        var encodedServerName = messageLogs[i].ServerName;
                        var encodedCompName = messageLogs[i].ComponentName;
                        var encodedSubCompName = messageLogs[i].SubComponentName;
                        if (encodedLogLevel == "Fatal") {
                            $messageTableBody.append('<tr style="background-color:Red"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        if (encodedLogLevel == "Warning") {
                            $messageTableBody.append('<tr style="background-color:Yellow"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        else {
                            $messageTableBody.append('<tr><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        i = i + 1;
                    });
                }
            };

If we want to load all the messages at first time also we can write code like this

$.connection.hub.start().done(function () {

            ew.server.getAllMessagesLog().done(function (messageLogs) {
                var i = 0;
                if ($('#hdnValue').val() == 1) {
                    $messageTableBody.empty();
                    $.each(messageLogs, function () {
                        var encodedName = messageLogs[i].Name;
                        var encodedEvent = messageLogs[i].EventID;
                        var encodedLogLevel = messageLogs[i].LogLevelName;
                        var encodedOCode = messageLogs[i].OperationCodeName;
                        var encodedServerName = messageLogs[i].ServerName;
                        var encodedCompName = messageLogs[i].ComponentName;
                        var encodedSubCompName = messageLogs[i].SubComponentName;
                        if (encodedLogLevel == "Fatal") {
                            $messageTableBody.append('<tr style="background-color:Red"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        if (encodedLogLevel == "Warning") {
                            $messageTableBody.append('<tr style="background-color:Yellow"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        else {
                            $messageTableBody.append('<tr><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        i = i + 1;
                    });
                }
            });
        });

GetNotification.cs : Complete Code of this page is

@{
    Layout = null;
}

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Message Watch</title>
    <style type="text/css">
        .container {
            background-color: #99CCFF;
            border: thick solid #808080;
            padding: 20px;
            margin: 20px;
        }
    </style>
    <style>
        body {
            font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
            font-size: 16px;
        }

        #messageTable table {
            border-collapse: collapse;
        }

            #messageTable table th, #messageTable table td {
                padding: 2px 6px;
            }

            #messageTable table td {
                text-align: right;
            }

        #messageTable .loading td {
            text-align: left;
        }
    </style>
</head>
<body>
    <div class="container">
        <div id="messageTable">
            <table border="1">
                <thead>
                    <tr><th>Message< /th><th>EventID</th><th>Component Name</th><th>OperationCodeName</th><th>ServerName</th><th>ComponentName</th><th>SubComponentName</th></tr>
                </thead>
                <tbody>
                  
                </tbody>
            </table>
            <input type="button" id="btnPause" name="Pause" value="Pause" />
            <input type="button" id="btnResume" name="Resume" value="Resume" />
            <input id="hdnValue" type="hidden" value="1" />

        </div>
    </div>
   
    <script src="~/Scripts/jquery-1.10.2.js"></script>
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/jquery.signalR-2.2.0.js"></script>
    <script src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
    <script src="~/signalr/hubs"></script>
    <script type="text/javascript">
        $(function () {
            $('#btnPause').click(function () {
                $('#hdnValue').val(0);
            });
            $('#btnResume').click(function () {
                $('#hdnValue').val(1);
            });
            var $messageTable = $('#messageTable');
            var $messageTableBody = $messageTable.find('tbody');
            // Declare a proxy to reference the hub.
            var ew = $.connection.notificationHub;
            //This method will fill all the Messages in case of any database change.
            ew.client.broadcastMessage = function (messageLogs) {
                // Html encode display name and message.
                var i = 0;
                if ($('#hdnValue').val() == 1) {
                    $messageTableBody.empty();

                    $.each(messageLogs, function () {
                        var encodedName = messageLogs[i].Name;
                        var encodedEvent = messageLogs[i].EventID;
                        var encodedLogLevel = messageLogs[i].LogLevelName;
                        var encodedOCode = messageLogs[i].OperationCodeName;
                        var encodedServerName = messageLogs[i].ServerName;
                        var encodedCompName = messageLogs[i].ComponentName;
                        var encodedSubCompName = messageLogs[i].SubComponentName;
                        if (encodedLogLevel == "Fatal") {
                            $messageTableBody.append('<tr style="background-color:Red"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        if (encodedLogLevel == "Warning") {
                            $messageTableBody.append('<tr style="background-color:Yellow"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        else {
                            $messageTableBody.append('<tr><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                        }
                        i = i + 1;
                    });
                }
            };

            //This method will fill all the Messages initially
            $.connection.hub.start().done(function () {
             
                ew.server.getAllMessagesLog().done(function (messageLogs) {
                    var i = 0;
                    if ($('#hdnValue').val() == 1) {
                        $messageTableBody.empty();
                        $.each(messageLogs, function () {
                            var encodedName = messageLogs[i].Name;
                            var encodedEvent = messageLogs[i].EventID;
                            var encodedLogLevel = messageLogs[i].LogLevelName;
                            var encodedOCode = messageLogs[i].OperationCodeName;
                            var encodedServerName = messageLogs[i].ServerName;
                            var encodedCompName = messageLogs[i].ComponentName;
                            var encodedSubCompName = messageLogs[i].SubComponentName;
                            if (encodedLogLevel == "Fatal") {
                                $messageTableBody.append('<tr style="background-color:Red"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                            }
                            if (encodedLogLevel == "Warning") {
                                $messageTableBody.append('<tr style="background-color:Yellow"><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                            }
                            else {
                                $messageTableBody.append('<tr><td>' + encodedName + '</td><td>' + encodedEvent + '</td><td>' + encodedLogLevel + '</td><td>' + encodedOCode + '</td><td>' + encodedServerName + '</td><td>' + encodedCompName + '</td><td>' + encodedSubCompName + '</td></tr>');
                            }
                            i = i + 1;
                        });
                    }
                });
            });
        });

    </script>
</body>

Run the application and you will find below result

Update some data in MessaageLog table

Insert into MessageLog values(4,102,3,2,13,3467,'Test123','DocClass.dll','GetData()','345','User is unable to get data','Sample Stack Trace',getdate())

All the client will updated real time with updated/Inserted data.

There are two buttons named Pause and Resume to pause and resume real time data.

 

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

VijayRana
Technical Lead
India India
Hi Myself Vijay having around 7 years of experience on Microsoft Technologies.

You may also be interested in...

Comments and Discussions

 
QuestionMy vote of 5 Pin
ThomaLuke17-Nov-17 4:48
professionalThomaLuke17-Nov-17 4:48 
GeneralMy vote of 5 Pin
Moshe Ventura18-Nov-15 1:11
memberMoshe Ventura18-Nov-15 1:11 
GeneralMy vote of 5 Pin
Rupesh Telang19-Oct-15 22:13
memberRupesh Telang19-Oct-15 22:13 
GeneralMy vote of 5 Pin
Ehsan Sajjad12-Oct-15 6:11
professionalEhsan Sajjad12-Oct-15 6:11 
QuestionMy vote is 5 Pin
SunilGupta04851-Oct-15 8:00
professionalSunilGupta04851-Oct-15 8:00 
GeneralMy voteof 5! Pin
Greg Good24-Sep-15 10:59
memberGreg Good24-Sep-15 10:59 
QuestionConfiguration? Pin
c-sharp-dork21-Sep-15 6:57
memberc-sharp-dork21-Sep-15 6:57 
QuestionMy Vote of 5 !!! Pin
Ankur11june20-Sep-15 22:42
memberAnkur11june20-Sep-15 22:42 
QuestionA small question Pin
Suvabrata Roy20-Sep-15 22:21
professionalSuvabrata Roy20-Sep-15 22:21 
AnswerRe: A small question Pin
Vijay Rana AON20-Sep-15 22:26
professionalVijay Rana AON20-Sep-15 22:26 
GeneralRe: A small question Pin
Suvabrata Roy20-Sep-15 22:27
professionalSuvabrata Roy20-Sep-15 22:27 
Question.. Pin
Member 1156416020-Sep-15 6:40
memberMember 1156416020-Sep-15 6:40 
GeneralMy vote of 5 Pin
Santhk20-Sep-15 6:27
professionalSanthk20-Sep-15 6:27 
QuestionVery nice! Pin
2374119-Sep-15 14:23
member2374119-Sep-15 14:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.171114.1 | Last Updated 19 Sep 2015
Article Copyright 2015 by VijayRana
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid