{"id":2435,"date":"2015-02-16T13:15:34","date_gmt":"2015-02-16T11:15:34","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=2435"},"modified":"2015-02-16T00:18:13","modified_gmt":"2015-02-15T22:18:13","slug":"real-time-website-data-using-signalr","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/","title":{"rendered":"Real-Time Website Data Using SignalR"},"content":{"rendered":"<p>When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a newer technology and I have always welcomed learning new technologies \u2013 especially when there is an immediate need to implement it, as opposed to reading about the technology and then never using it again.<\/p>\n<p>So I started where everyone else starts: Google. I found out quickly that most, if not all, of the results that I turned up with example code were making use of the same thing: a Chat application. This would have been perfect for me, if that was what I was looking to build\u2026 which it wasn\u2019t.<\/p>\n<p>So I copied the code, and within five minutes, I had a Chat application up and running. It demonstrated SignalR\u2019s functionality \u2013 how it provides a path for the server to communicate with its clients, and how clients communicate with a server Hub. Unfortunately, it was far from what I was looking to accomplish.<\/p>\n<h2>Background<\/h2>\n<p>I have a \u201cwebsite\u201d that is implemented with ExtJS. It then communicates with an \u201cAPI site\u201d implemented in ASP.NET to communicate with the database. I have a page that lists out records that are entered into the website. These records can be entered on this page through my browser, or they could be entered from another browser elsewhere, anywhere.<\/p>\n<p>The way it is currently updating, and how I have implemented in the past for similar situations, is to send a request to the server at one-minute intervals, and then redraw the list.<\/p>\n<p>This works fine, but if a record is added to the website from another browser just one second after the list is updated, it will take nearly another minute to see that record on the other browser that is displaying the list of records.<\/p>\n<p>Enter SignalR and its real-time updating.<\/p>\n<h2>Implementation<\/h2>\n<p>Enough history, here is my implementation:<\/p>\n<p><strong>1.<\/strong> Using <a href=\"https:\/\/www.nuget.org\/\" target=\"_blank\">Nuget<\/a>, I installed SignalR and all of its associated packages into my API site.<\/p>\n<p>After it installed, it brought up a README file with the code for the \u201cStartup.cs\u201d file that it instructs you to create.<\/p>\n<p>I created that \u201cStartup.cs\u201d file in the \u201cApp_Start\u201d folder.<\/p>\n<p>I later found that on the ASP.Net website, it describes how to establish a cross-domain (<a href=\"http:\/\/en.wikipedia.org\/wiki\/Cross-origin_resource_sharing\" target=\"_blank\">CORS<\/a>) connection, providing <a href=\"http:\/\/www.asp.net\/signalr\/overview\/guide-to-the-api\/hubs-api-guide-javascript-client#crossdomain\" target=\"_blank\">this \u201cStartup.cs\u201d file<\/a>, which I am now using. You will need to use Nuget and install the \u201cMicrosoft.Own.Cors\u201d package also.<\/p>\n<p>Here is my \u201cStartup.cs\u201d file:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">using Microsoft.Owin;\r\n\tusing Owin;\r\n\tusing Microsoft.Owin.Cors;\r\n\tusing Microsoft.AspNet.SignalR;\r\n\r\n\t&#x5B;assembly: OwinStartup(typeof(API.Startup))]\r\n\tnamespace API\r\n\t{\r\n\t    public class Startup\r\n\t    {\r\n\t        public void Configuration(IAppBuilder app)\r\n\t        {\r\n\t            \/\/ THIS IS THE DEFAULT MAPPING TO '\/signalr'\r\n\t            \/\/app.MapSignalR();\r\n\r\n\t            \/\/ Branch the pipeline here for requests that start with '\/signalr'\r\n\t            app.Map('\/signalr', map =&gt;\r\n\t            {\r\n\t                \/\/ Setup the cors middleware to run before SignalR.\r\n\t                \/\/ By default this will allow all origins. You can\r\n\t                \/\/ configure the set of origins and\/or http verbs by\r\n\t                \/\/ providing a cors options with a different policy.\r\n\t                map.UseCors(CorsOptions.AllowAll);\r\n\r\n\t                var hubConfiguration = new HubConfiguration\r\n\t                {\r\n\t                    \/\/ You can enable JSONP by uncommenting line below.\r\n\t                    \/\/ JSONP requests are insecure but some older browsers (and some\r\n\t                    \/\/ versions of IE) require JSONP to work cross domain\r\n\t                    \/\/ EnableJSONP = true\r\n\t                };\r\n\r\n\t                \/\/ Run the SignalR pipeline. We're not using MapSignalR\r\n\t                \/\/ since this branch already runs under the '\/signalr' path.\r\n\t                map.RunSignalR(hubConfiguration);\r\n\t            });\r\n\t        }\r\n\t    }\r\n\t}<\/pre>\n<p><strong>2.<\/strong> When SignalR was installed, it created jQuery and SignalR .js files in the \u201cScripts\u201d directory. I first copied those files from the API site to the website for more efficient loading.<\/p>\n<p>I then included those two local .js files in the \u201cViews\/Shared\/_Layout.cshtml\u201d file located on my website, and then a reference to the \u201csignalr\/hubs\u201d virtual directory created by SignalR on the API site:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">&lt;script src='\/Content\/scripts\/jquery-1.9.1.js'&gt;&lt;\/script&gt;\r\n\t&lt;script src='\/Content\/scripts\/jquery.signalR-2.1.1.min.js'&gt;&lt;\/script&gt;\r\n\t&lt;!-- REFERENCE THE AUTO-GENERATED SIGNALR HUB SCRIPT THAT RESIDES ON THE API  --&gt;\r\n\t&lt;script src='\/API\/signalr\/hubs'&gt;&lt;\/script&gt;<\/pre>\n<p><strong>3.<\/strong> And then under that, I have the client side code needed to connect to the SignalR \u201cHub,\u201d to define the method that the server will call on each of its connected clients, and some other nice-to-haves, such as to turn client-side logging on and to reconnect to the Hub if it becomes disconnected.<\/p>\n<p>This reconnecting method has really helped me a lot as there are times where SignalR does not connect initially, and then this reconnecting method kicks in. It will try to connect every five seconds until it connects successfully.<\/p>\n<p>Here is that code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;script type='text\/javascript'&gt;\r\n\t$(function () {\r\n\t\t\/\/ ************************************************************************\r\n\t\t\/\/ TURN ON SIGNALR CLIENT-SIDE LOGGING\r\n\t\t$.connection.hub.logging = true;\r\n\r\n\t\t\/\/ METHOD CALLED FROM SERVER-SIDE CODE\r\n\t\t$.connection.APIHub.client.refreshList = function () {\r\n\t\t\t\/\/ DETERMINE IF CLIENT HAS CHECKIN OPEN\r\n\t\t\tvar listOpen = false;\r\n\t\t\tvar windows = Ext.ComponentQuery.query('openitems')&#x5B;0].items;\r\n\t\t\tfor (var i = windows.items.length - 1; i &gt;= 0; i--) {\r\n\t\t\t\tvar toolbar = windows.items&#x5B;i];\r\n\t\t\t\tvar target = toolbar.items.items&#x5B;0].id;\r\n\t\t\t\tlistOpen = target.indexOf('list') &gt; 0 ? true : false;\r\n\t\t\t\tif (listOpen) break;\r\n\t\t\t}\r\n\r\n\t\t\t\/\/ ONLY REFRESH EXTJS STORE IF LIST IS OPEN\r\n\t\t\tif (listOpen) {\r\n\t\t\t\tvar listStore = Ext.getStore('List.store.ListLocations');\r\n\t\t\t\tlistStore.load({ params: { 'locationId': Session.user.LocationId } });\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\t\/\/ START CONNECTION USING THE USER'S LOCATION ID\r\n\t\t$.connection.hub.start()\r\n\t\t\t.done(function () {\r\n\t\t\t\tconsole.log('SignalR connected, connection id = ' + $.connection.hub.id);\r\n\t\t\t\tconsole.log('Session.user.LocationId = ' + Session.user.LocationId);\r\n\t\t\t\t$.connection.iCHub.server.connectToHub(Session.user.LocationId);\r\n\t\t\t})\r\n\t\t\t.fail(function (data) {\r\n\t\t\t\tconsole.log('SignalR failed to connect: ' + data);\r\n\t\t});\r\n\r\n\t\t\/\/ REPORT CONNECTION ERROR\r\n\t\t$.connection.hub.error(function (error) {\r\n\t\t\tconsole.log('SignalR error: ' + error);\r\n\t\t});\r\n\r\n\t\t\/\/ IF DISCONNECTED, ATTEMPT RESTART AFTER 5 SECONDS\r\n\t\t$.connection.hub.disconnected(function () {\r\n\t\t\tsetTimeout(function () {\r\n\t\t\t\t$.connection.hub.start()\r\n\t\t\t\t\t.done(function () {\r\n\t\t\t\t\t\tconsole.log('SignalR reconnected, connection id = ' + $.connection.hub.id);\r\n\t\t\t\t\t\t$.connection.iCHub.server.connectForCheckins(Session.user.LocationId);\r\n\t\t\t\t\t})\r\n\t\t\t\t\t.fail(function (data) {\r\n\t\t\t\t\t\tconsole.log('SignalR failed to reconnect: ' + data);\r\n\t\t\t\t});\r\n\t\t\t}, 5000);\r\n\t\t});\r\n\r\n\t\t\/\/ THIS ENSURES CONNECTION IS STOPPED WHEN WINDOW IS UNLOADED\r\n\t\twindow.onbeforeunload = function (e) {\r\n\t\t\t$.connection.hub.stop();\r\n\t\t};\r\n\t\t\/\/ ************************************************************************\r\n\t});\r\n\t&lt;\/script&gt;\r\n<\/pre>\n<p><strong>4.<\/strong> On the API site, I then created a folder named \u201chubs\u201d and created my \u201cHub\u201d file there. To create your Hub file, you will right-click on the folder. Click \u201cAdd\u201d and then choose \u201cSignalR Hub Class (v2)\u201d and name it whatever you want. I named mine \u201cAPIHub.\u201d This will add a default hub with a function that, when called from server side code, would call the function \u201chello()\u201d on all clients that are connected to the hub, which isn\u2019t useful for my purposes, but may be to someone else.<\/p>\n<p>I need to notify clients of new records based on the \u201cLocationId\u201d they are watching. So if a record gets added to the database for that LocationId from any other browser, and I am monitoring that LocationId on my browser, I want my list to update.<\/p>\n<p>This is where using SignalR Groups comes into play. Groups provide a way to map a \u201cconnectionid\u201d that SignalR gives to each connected client to a specific named User, which in my case will represent a LocationId.<\/p>\n<p>This is important in my usage, as you will see later on.<\/p>\n<p>Here is the APIHub.cs file:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">using System;\r\n\tusing System.Collections.Generic;\r\n\tusing System.Web;\r\n\tusing Microsoft.AspNet.SignalR;\r\n\r\n\tnamespace API\r\n\t{\r\n\t    public class APIHub : Hub\r\n\t    {\r\n\t        \/\/ CALLED FROM EACH CLIENT THAT CONNECTS TO HUB\r\n\t        public void ConnectToHub(string locationId)\r\n\t        {\r\n\t            \/\/ MAP LOGICAL USER 'LOCATIONID' TO THE 'CONNECTIONID' USING GROUPS.\r\n\t            \/\/ THIS ALLOWS US TO SEND TO THE 'GROUP' OUTSIDE OF THE HUB, WHERE THERE\r\n\t            \/\/ IS NO CONCEPT OF THE 'CONNECTIONID'\r\n\t            Groups.Add(Context.ConnectionId, locationId);\r\n\t            System.Diagnostics.Debug.WriteLine('HUB: CONNECTFORCHECKINS: ' + locationId);\r\n\t        }\r\n\t    }\r\n\t}<\/pre>\n<p><strong>5.<\/strong> As you can see above, my Hub has only a single method, which is called from clients when they want to connect to the Hub, passing the LocationId that they want to monitor. For my purposes, the communication from the server to the client will happen outside of the Hub, therefore I need the \u201cHubUtility\u201d class file.<\/p>\n<p>The reason for this is because it implements an interface that is in the namespace \u201cCore,\u201d which is where my repository class is that will need to trigger the call back to the specific clients that are monitoring a LocationId.<\/p>\n<p>Since I can\u2019t call Hub methods directly from outside of the context of the Client-Hub connection, I must use this HubUtility class and it will make use of SignalR\u2019s ability to use a \u201cHubContext.\u201d It will then use it to trigger the call-back to its connected clients.<\/p>\n<p>I place this HubUtility class in the hubs directory on the API site so it is in the same directory as our Hub file.<\/p>\n<p>Here is the \u201cHubUtility.cs\u201d:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">using System;\r\n\tusing System.Collections.Generic;\r\n\tusing System.Web;\r\n\tusing Microsoft.AspNet.SignalR;\r\n\tusing Core;\r\n\r\n\tnamespace API\r\n\t{\r\n\t    public class HubUtility : IMessageHub\r\n\t    {\r\n\t        public void RefreshListOnClient(string locationId)\r\n\t        {\r\n\t            \/\/ SETUP HUB CONTEXT TO THE 'APIHUB'\r\n\t            var context = Microsoft.AspNet.SignalR.GlobalHost.ConnectionManager.GetHubContext&lt;APIHub&gt;();\r\n\r\n\t            \/\/ TRIGGER METHOD ON APPROPRIATE CLIENTS THAT CONNECTED WITH 'LOCATIONID'\r\n\t            context.Clients.Group(locationId).refreshList();\r\n\r\n\t            \/\/ OUTPUT THAT METHOD WAS TRIGGERED AND FOR WHAT 'LOCATIONID'\r\n\t            System.Diagnostics.Debug.WriteLine('HUB: RefreshListOnClient: ' + locationId);\r\n\t        }\r\n\t    }\r\n\t}<\/pre>\n<p>And here is the \u201cIMessageHub.cs\u201d Interface that I placed with the rest of my \u201cCore\u201d files on the API site:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">using System;\r\n\r\n\tnamespace ityCity.Core\r\n\t{\r\n\t    public interface IMessageHub\r\n\t    {\r\n\t        void RefreshCheckinListOnClient(string client);\r\n\t    }\r\n\t}<\/pre>\n<p><strong>6.<\/strong> We use \u201cAutofac\u201d in our application so in the API site\u2019s \u201cGlobal.asax.cs,\u201d we need to register the HubUtility so it can be found. If you don\u2019t use Autofac then this will not be necessary.<\/p>\n<p>In the \u201cApplication_Start\u201d method, I added the following under the config register statements:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">var builder = new ContainerBuilder();\r\nbuilder.RegisterType&lt;HubUtility&gt;().AsImplementedInterfaces().InstancePerApiRequest();<\/pre>\n<p><strong>7.<\/strong>\u00a0In my repository class file, we use dependency injection to inject an object that is of the interface \u201cIMessageHub\u201d which HubUtility implements.<\/p>\n<p>This will allow me to make my call back to my HubUtility class method passing the appropriate LocationId, which will in turn make use of the \u201cAPIHub\u201d context, and will trigger the client side method call on clients that have connected to the Hub passing that particular \u201cLocationId.\u201d<\/p>\n<p>Here is that pertinent code:<\/p>\n<pre class=\"brush: perl; title: ; notranslate\" title=\"\">...\r\n\t\/\/ INSTANCE VARIABLE\r\n\tprivate IMessageHub _messageHub;\r\n\t...\r\n\t\/\/ DI INTO CONSTRUCTOR\r\n\tpublic Repository(..., IMessageHub messageHub)\r\n\t{\r\n\t\t...\r\n\t\tthis._messageHub = messageHub;\r\n\t}\r\n\t...\r\n\t\/\/ WITHIN SPECIFIC METHOD TO COMMUNICATE THAT RECORD WAS ADDED TO SITE\r\n\tthis._messageHub.RefreshListOnClient( record.locid );<\/pre>\n<h2>Conclusion<\/h2>\n<p>SignalR makes using web sockets very easy to facilitate real-time updating of data on a website. There is also the use of SQL Dependency that would allow the ability to monitor specific data within your database and trigger calls to clients when that data is changed in the database. We chose to not use this method as our data may not always be in the database. In fact, it is changing to be in a remote CRM located elsewhere that we are communicating with using their API.<\/p>\n<p>Doing it the way we have implemented it, using the HubContext, we can trigger the call whether we continue using a local database or some other remote data repository such as a CRM.<\/p>\n<p>I am looking forward to finding new ways to make use of SignalR in the future. I hope this helps at least one other person, with either introducing them to the power of SignalR or demonstrating another possible usage, other than a Chat application.<\/p>\n<p>Although my implementation may have some unique circumstances due to the complexity of how the application was constructed, I am hopeful that it has demonstrated how SignalR can be used outside of just the Client-Hub usage that a Chat application uses, and shows how you can use SignalR to trigger communication with connected clients from deep inside your application.<\/p>\n<p>I feel that I have only scratched the surface of the possibilities that SignalR has to offer. For some more excellent information regarding SignalR please see <a href=\"https:\/\/keyholesoftware.com\/2014\/05\/19\/signalr-in-a-nutshell\/\" target=\"_blank\">Brad Trebilcock\u2019s post<\/a>. Anywhere data is displayed and updated, SignalR may possibly hold the answer to a more useful website and, maybe more importantly, a better user experience.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td><span class=\"reference\">Reference: <\/span><\/td>\n<td><a href=\"https:\/\/keyholesoftware.com\/2015\/02\/02\/real-time-data-using-signalr\/\">Real-Time Website Data Using SignalR<\/a> from our <a href=\"http:\/\/www.webcodegeeks.com\/wcg\/\">WCG partner<\/a> Keyhole Software at the <a href=\"http:\/\/keyholesoftware.com\/\">Keyhole Software<\/a> blog.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a newer technology and I have always welcomed learning new technologies \u2013 especially when there is an immediate need to implement it, as opposed to reading about &hellip;<\/p>\n","protected":false},"author":22,"featured_media":1865,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19],"tags":[94],"class_list":["post-2435","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-net","tag-signalr"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Real-Time Website Data Using SignalR - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Real-Time Website Data Using SignalR - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:author\" content=\"http:\/\/facebook.com\/keyholesoftware\" \/>\n<meta property=\"article:published_time\" content=\"2015-02-16T11:15:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Keyhole Software\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@http:\/\/twitter.com\/keyholesoftware\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Keyhole Software\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\"},\"author\":{\"name\":\"Keyhole Software\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/10701460d97ebefdaf658a4f4535fff2\"},\"headline\":\"Real-Time Website Data Using SignalR\",\"datePublished\":\"2015-02-16T11:15:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\"},\"wordCount\":2027,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg\",\"keywords\":[\"SignalR\"],\"articleSection\":[\"ASP.NET\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\",\"name\":\"Real-Time Website Data Using SignalR - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg\",\"datePublished\":\"2015-02-16T11:15:34+00:00\",\"description\":\"When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ASP.NET\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/asp-net\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Real-Time Website Data Using SignalR\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/10701460d97ebefdaf658a4f4535fff2\",\"name\":\"Keyhole Software\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/68be341bef51b95ced09befd6a7e0ca930461d95f3a64285e03e7925b8f5de47?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/68be341bef51b95ced09befd6a7e0ca930461d95f3a64285e03e7925b8f5de47?s=96&d=mm&r=g\",\"caption\":\"Keyhole Software\"},\"description\":\"Keyhole is a midwest-based consulting firm with a tight-knit technical team. We work primarily with Java, JavaScript and .NET technologies, specializing in application development. We love the challenge that comes in consulting and blog often regarding some of the technical situations and technologies we face.\",\"sameAs\":[\"http:\/\/keyholesoftware.com\/\",\"http:\/\/facebook.com\/keyholesoftware\",\"http:\/\/linkedin.com\/company\/keyhole-software\",\"https:\/\/x.com\/http:\/\/twitter.com\/keyholesoftware\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/keyhole-software\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Real-Time Website Data Using SignalR - Web Code Geeks - 2026","description":"When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/","og_locale":"en_US","og_type":"article","og_title":"Real-Time Website Data Using SignalR - Web Code Geeks - 2026","og_description":"When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a","og_url":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_author":"http:\/\/facebook.com\/keyholesoftware","article_published_time":"2015-02-16T11:15:34+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg","type":"image\/jpeg"}],"author":"Keyhole Software","twitter_card":"summary_large_image","twitter_creator":"@http:\/\/twitter.com\/keyholesoftware","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Keyhole Software","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/"},"author":{"name":"Keyhole Software","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/10701460d97ebefdaf658a4f4535fff2"},"headline":"Real-Time Website Data Using SignalR","datePublished":"2015-02-16T11:15:34+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/"},"wordCount":2027,"commentCount":2,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg","keywords":["SignalR"],"articleSection":["ASP.NET"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/","url":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/","name":"Real-Time Website Data Using SignalR - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg","datePublished":"2015-02-16T11:15:34+00:00","description":"When I was tasked with using SignalR to implement the real-time updating of data on a project I was working on, I was excited. Namely because it is a","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/asp-dotnet-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/asp-net\/real-time-website-data-using-signalr\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"ASP.NET","item":"https:\/\/www.webcodegeeks.com\/category\/asp-net\/"},{"@type":"ListItem","position":3,"name":"Real-Time Website Data Using SignalR"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/10701460d97ebefdaf658a4f4535fff2","name":"Keyhole Software","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/68be341bef51b95ced09befd6a7e0ca930461d95f3a64285e03e7925b8f5de47?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/68be341bef51b95ced09befd6a7e0ca930461d95f3a64285e03e7925b8f5de47?s=96&d=mm&r=g","caption":"Keyhole Software"},"description":"Keyhole is a midwest-based consulting firm with a tight-knit technical team. We work primarily with Java, JavaScript and .NET technologies, specializing in application development. We love the challenge that comes in consulting and blog often regarding some of the technical situations and technologies we face.","sameAs":["http:\/\/keyholesoftware.com\/","http:\/\/facebook.com\/keyholesoftware","http:\/\/linkedin.com\/company\/keyhole-software","https:\/\/x.com\/http:\/\/twitter.com\/keyholesoftware"],"url":"https:\/\/www.webcodegeeks.com\/author\/keyhole-software\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/2435","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/22"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=2435"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/2435\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/1865"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=2435"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=2435"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=2435"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}