Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

SignalR - Message Watch Application in C# with Database Notifications

0.00/5 (No votes)
19 Sep 2015 1  
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>

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here