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.
PM> Install-Package Microsoft.AspNet.SignalR
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.
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();
}
}
}
<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>
<script src="/signalr/hubs" type="text/javascript"></script>
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>
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)
{
...
}
}
}
On the server side we should provide a persistent connection. There are several variants here and we will consider two of them:
On the client side we initialize web socket connection and process incoming messages with the help of the scheduler.dataProcessor class.
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>
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);
}
}
}
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.
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
);
}
}
}