Download Free Demos

Live Update

Live Update is a mode that provides synchronous data update in real time. When some of the users makes a change, it becomes visible to all others immediately.

Live Update with SignalR

Server side

  • Firstly, we install the SignalR library. The easiest way to install the library is to run the following command in the NuGet manager console:
PM> Install-Package Microsoft.AspNet.SignalR
  • Then, we create a hub (SignalR will handle all the connection stuff on both client and server sides, ensuring that the connection stays open and active):
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.Hubs;
namespace Scheduler.SignalR.Sample
{
    [HubName("schedulerHub")]
    public class SchedulerHub : Hub
    {
        public void Send(string update)
        {
            this.Clients.All.addMessage(update);
        }
    }
}

By setting this.Clients.All.addMessage(update), we are telling all the clients to call the addMessage() function when they make a change in the scheduler. addMessage() is called from the server via our persistent connection.

  • We add a new startup class: right-click the project, then click Add → New Item → OWIN Startup Class. If your version of the Visual Studio does not have a template for OWIN Startup Class, simply create an empty class named Startup with following code:
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(Scheduler.SignalR.Sample.Startup))]
namespace Scheduler.SignalR.Sample
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

Client side

  • We add references to jQuery and jQuery.signalR:
<script src="Scripts/jquery-3.1.0.js" type="text/javascript"></script>
<script src="Scripts/jquery.signalR-2.2.1.min.js" type="text/javascript"></script>
  • We add the reference to dynamically generated script that will contain the client hub:
<script src="/signalr/hubs" type="text/javascript"></script>
  • Finally, we initialize the hub connection and attach it to the scheduler's dataprocessor:
var hub = $.connection.schedulerHub;
scheduler.dataProcessor.attachEvent("onLocalUpdate", function (data) {
     hub.server.send(JSON.stringify(data));
});
hub.client.addMessage = function (message) {
     scheduler.dataProcessor.applyChanges(JSON.parse(message));
};
$.connection.hub.start();

When some change occurs in the scheduler, the onLocalUpdate event occurs and the dataprocessor passes action data to the hub.server.send method. The client hub receives this data and calls the addMessage function which parses the message data, applies changes to the scheduler and shares information with other clients.

<!DOCTYPE html>
<html>
<head>
    <title>Scheduler SignalR</title>
    <script src="@Url.Content("~/Scripts/jquery-3.1.0.js")" ></script>
    <script src="@Url.Content("~/Scripts/jquery.signalR-2.2.1.min.js")" ></script>
    <script src="@Url.Content("~/signalr/hubs")" ></script>
 
</head>
<body>
@Html.Raw(Model.Render())
<script>
    (function () {
        var hub = $.connection.schedulerHub;
 
        scheduler.dataProcessor.attachEvent("onLocalUpdate", function (data) {
            hub.server.send(JSON.stringify(data));
        });
        hub.client.addMessage = function (message) {
            scheduler.dataProcessor.applyChanges(JSON.parse(message));
        };
 
        $.connection.hub.start();
    })()
</script> </body> </html>

Common Implementation

Scheduler configuration

To work in the Live Update mode, scheduler can be initialized and configured in a standard way (see details in the related article.

The only addition required is enabling the LiveUpdates extension:

using System;
using System.Web;
using System.Web.Mvc;
 
using DHTMLX.Scheduler;
using DHTMLX.Common;
using DHTMLX.Scheduler.Data;
namespace LiveUpdateScheduler.Controllers
{
    public class Home: Controller
    {
        public ActionResult Index()
        {
            var scheduler = new DHXScheduler(this);
            scheduler.Extensions.Add(SchedulerExtensions.Extension.LiveUpdates); //this line enables the LiveUpdates extension
            scheduler.LoadData = true;
            scheduler.EnableDataprocessor = true;
 
            return View(scheduler);
        }
 
        public ContentResult Data()
        {
           ...
        }
 
        public ContentResult Save(int? id, FormCollection actionValues)
        {
            ...
        }
    }
}

Server side

On the server side we should provide a persistent connection. There are several variants here and we will consider two of them:

  • WebSockets (doesn't require any third-party libraries but natively supported only in IIS 8+, Windows 8 or Windows Server 2012. Support for browsers: Firefox 15+, Chrome 22+, Safari 6+, Opera 21+, IE10+)
  • SignalR async library (universal way supported by all browsers)

Client side

On the client side we initialize web socket connection and process incoming messages with the help of the scheduler.dataProcessor class.

Live Update with WebSockets

Client side

  • We initialize web socket connection and attach it to the scheduler's dataprocessor (we use the 'onLocalUpdate' event and the 'applyChanges' method of DHXScheduler.dataProcessor that are defined in the LiveUpdates extension):
var socket = new WebSocket('ws://@Request.Url.Authority/api/WebSocket');
scheduler.dataProcessor.attachEvent("onLocalUpdate", function (data) {
     socket.send(JSON.stringify(data));
});
socket.onmessage = function (ev) {
    scheduler.dataProcessor.applyChanges(JSON.parse(ev.data));
};

The onLocalUpdate event fires each time a user makes a change.

So, when some change occurs in the scheduler, dataprocessor passes action data to the WebSocket.send method. The socket receives this data and calls the onmessage event handler which parses the message data, applies changes to the scheduler and shares information with other clients.

<!DOCTYPE html>
<html>
<head>
    <title>Scheduler & WebSockets</title>
</head>
<body>
    @Html.Raw(Model.Render())
    <script>
        (function(){
            var socket = new WebSocket('ws://@Request.Url.Authority/api/WebSocket');
            scheduler.dataProcessor.attachEvent("onLocalUpdate", function (data) {
                socket.send(JSON.stringify(data));
            });
            socket.onmessage = function (ev) {
                scheduler.dataProcessor.applyChanges(JSON.parse(ev.data));
            };
        })()
</script>
</body> </html>

Server side

  • Firstly, we create a collection to store all connected clients. We do it right in the Global.asax.cs:
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using Microsoft.Web.WebSockets;
namespace Sockets
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            Application["connections"] = new WebSocketCollection();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    }
}
  • Secondly, we create a class to handle web sockets connections:
using System;
using Microsoft.Web.WebSockets;
public class DHXWebSocketListener : WebSocketHandler
{
    public DHXWebSocketListener(WebSocketCollection clients)
    {
        connections = clients;
    }
    private readonly WebSocketCollection connections;
    public override void OnOpen()
    {
        connections.Add(this);
    }
    public override void OnClose()
    {
        connections.Remove(this);
    }
    public override void OnMessage(string message)
    {
        connections.Broadcast(message);
    }
}

The code does a basic routine: adds/removes a socket to/from application's socket connection collection. When a socket receives a new message, the code sends it to the other clients.

  • And finally we need a controller to handle new clients connections:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Web.WebSockets;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace Sockets.Controllers
{
    public class WebSocketController : ApiController
    {
        public HttpResponseMessage Get()
        {
            HttpContext.Current.AcceptWebSocketRequest(
                new DHXWebSocketListener(
                    (WebSocketCollection)HttpContext.Current.Application["connections"])//global list of connections
            );
            return new HttpResponseMessage(
                HttpStatusCode.SwitchingProtocols
            );
        }
    }
}

Was this article helpful?

Yes No