SignalR Binding
SignalR allows you to add real-time functionality to your Scheduler. SignalR takes care of everything behind the scenes that makes real-time client-to-server and server-to-client communications possible. This is useful in collaborative scenarios where multiple parties are using the Scheduler simultaneously or in apps that utilize push notifications.
You can use it with both the Telerik UI helpers for MVC and Core because they wrap the Kendo UI for jQuery Scheduler.
For a runnable example, refer to the demo on SignalR binding of the Scheduler component.
As of the ASP.NET MVC R2 2018 release, the suite provides SignalR support for its components.
This article provides step-by-step instructions on using SignalR binding with the Scheduler.
SignalR Versions
Two versions of SignalR exist—ASP.NET Core SignalR and ASP.NET SignalR. It is important to note that ASP.NET Core SignalR is not compatible with clients or servers for ASP.NET SignalR. This means, for example, that you cannot connect a ASP.NET SignalR server to a client using ASP.NET Core SignalR client library.
The table below highlights the major differences between ASP.NET SignalR and ASP.NET Core SignalR:
ASP.NET SignalR | ASP.NET Core SignalR | |
---|---|---|
Server NuGet package | Microsoft.AspNet.SignalR | None. Included in the Microsoft.AspNetCore.App shared framework. |
Client NuGet packages | Microsoft.AspNet.SignalR.Client Microsoft.AspNet.SignalR.JS | Microsoft.AspNetCore.SignalR.Client |
JavaScript client npm package | signalr | @microsoft/signalr |
Server app type | ASP.NET (System.Web) or OWIN Self-Host | ASP.NET Core |
Supported server platforms | .NET Framework 4.5 or later | .NET Core 3.0 or later |
For further details, refer to the official Microsoft documentation.
Setting Up ASP.NET SignalR Service
Complete details on setting up an ASP.NET SignalR service are available in Microsoft's documentation. In general, the following steps must be taken:
- Add the
Microsoft.AspNet.SignalR
NuGet package. - Add an OWIN Startup Class and the SignalR configuration.
- Ensure the hubs are mapped.
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here, for example, the Demo Service configuration is below
app.MapSignalR("/signalr/hubs", new HubConfiguration
{
EnableJSONP = true
});
}
}
Configuring the Hub
SignalR uses hubs to communicate between clients and servers. A hub is a high-level pipeline that allows the client-server communication. The SignalR Hubs API enables you to call methods on connected clients from the server.
The example below demonstrates a sample Hub implementation:
public class MeetingHub(SampleEntitiesDataContext context) : Hub
{
public override Task OnConnectedAsync()
{
Groups.AddToGroupAsync(Context.ConnectionId, GetGroupName());
return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception e)
{
Groups.RemoveFromGroupAsync(Context.ConnectionId, GetGroupName());
return base.OnDisconnectedAsync(e);
}
public IEnumerable<MeetingSignalR> Read()
{
var createdAt = DateTime.Now;
var meetings = context.Meetings
.ToList() // Execute the query because Linq to SQL doesn't get Guid.NewGuid()
.Select(meeting => new MeetingSignalR
{
ID = Guid.NewGuid(),
Title = meeting.Title,
Start = DateTime.SpecifyKind(meeting.Start, DateTimeKind.Utc),
End = DateTime.SpecifyKind(meeting.End, DateTimeKind.Utc),
StartTimezone = meeting.StartTimezone,
EndTimezone = meeting.EndTimezone,
Description = meeting.Description,
IsAllDay = meeting.IsAllDay,
RoomID = meeting.RoomID,
RecurrenceRule = meeting.RecurrenceRule,
RecurrenceException = meeting.RecurrenceException,
RecurrenceID = meeting.RecurrenceID,
Attendees = meeting.MeetingAttendees.Select(m => m.AttendeeID).ToArray(),
CreatedAt = createdAt = createdAt.AddMilliseconds(1)
}).ToList();
return meetings;
}
public void Update(MeetingSignalR meeting)
{
Clients.OthersInGroup(GetGroupName()).SendAsync("update", meeting);
}
public void Destroy(MeetingSignalR meeting)
{
Clients.OthersInGroup(GetGroupName()).SendAsync("destroy", meeting);
}
public MeetingSignalR Create(MeetingSignalR meeting)
{
meeting.ID = Guid.NewGuid();
meeting.CreatedAt = DateTime.Now;
Clients.OthersInGroup(GetGroupName()).SendAsync("create", meeting);
return meeting;
}
public string GetGroupName()
{
return GetRemoteIpAddress();
}
public string GetRemoteIpAddress()
{
return Context.GetHttpContext()?.Connection.RemoteIpAddress?.ToString();
}
}
Including the Client-Side Library
Ensure the client-side library matches the server-side library version. Connecting an ASP.NET SignalR server to a client using ASP.NET Core SignalR client library and vice versa is not supported.
Configuring the ASP.NET SignalR Client-Side Hub
If you use the ASP.NET SignalR service, you must use the ASP.NET SignalR client-side library.
- Add a reference to the client-side SignalR library.
- Initialize a hub.
- Start the hub.
For additional guidance on the client-side API of the ASP.NET SignalR library, refer to Microsoft's documentation. The example below demonstrates the hub configuration:
<script src="Scripts/jquery.signalR-2.2.1.min.js"></script>
<script>
var hubUrl = "path/to/hub";
var connection = $.hubConnection(hubUrl, { useDefaultPath: false });
var hub = connection.createHubProxy("meetings");
var hubStart = connection.start({ jsonp: true });
</script>
Configuring the Scheduler DataSource
The next steps describe how to set up the Transport
configuration of the Scheduler's DataSource to connect to the SignalR Hub.
Instruct the DataSource to use SignalR protocol for transmitting and operating with data in real-time.
@(Html.Kendo().Scheduler<MeetingSignalRViewModel>()
.Name("scheduler")
.Date(DateTime.Now)
.StartTime(DateTime.Now.AddHours(-3))
.Height(600)
.Views(views =>
{
views.DayView();
views.WeekView(weekView => weekView.Selected(true));
views.MonthView();
views.AgendaView();
views.TimelineView();
})
.Timezone("Etc/UTC")
.Resources(resource =>
{
resource.Add(m => m.RoomID)
.Title("Room")
.DataTextField("Text")
.DataValueField("Value")
.DataColorField("Color")
.BindTo(new[] {
new { Text = "Meeting Room 101", Value = 1, Color = "#6eb3fa" },
new { Text = "Meeting Room 201", Value = 2, Color = "#f58a8a" }
});
resource.Add(m => m.Attendees)
.Title("Attendees")
.Multiple(true)
.DataTextField("Text")
.DataValueField("Value")
.DataColorField("Color")
.BindTo(new[] {
new { Text = "Alex", Value = 1, Color = "#f8a398" },
new { Text = "Bob", Value = 2, Color = "#51a0ed" },
new { Text = "Charlie", Value = 3, Color = "#56ca85" }
});
})
.DataSource(dataSource => dataSource
.SignalR()
.Transport(tr => tr
.Promise("hubStart") // The promise returned by the start method of the SignalR connection.
.Hub("hub") // The SignalR HubConnection object created by the hub connection.
.Client(c => c
.Read("read")
.Create("create")
.Update("update")
.Destroy("destroy"))
.Server(s => s
.Read("read")
.Create("create")
.Update("update")
.Destroy("destroy")))
.Schema(schema => schema
.Model(model =>
{
model.Id(m => m.ID);
model.Field(m => m.ID).Editable(false);
model.Field("start", typeof(DateTime)).From("Start");
model.Field("end", typeof(DateTime)).From("End");
model.Field("title", typeof(string)).From("Title");
model.Field("description", typeof(string)).From("Description");
model.Field("recurrenceID", typeof(int)).From("RecurrenceID");
model.Field("recurrenceRule", typeof(string)).From("RecurrenceRule");
model.Field("recurrenceException", typeof(string)).From("RecurrenceException");
model.Field("isAllDay", typeof(bool)).From("IsAllDay");
model.Field("startTimezone", typeof(string)).From("StartTimezone");
model.Field("endTimezone", typeof(string)).From("EndTimezone");
})
)
)
)
SignalR with Push Notifications
The following example demonstrates a sample implementation of a Scheduler that uses SignalR to show push notifications.
$(document).ready(function() {
var hubUrl = "path/to/hub";
var hub = new signalR.HubConnectionBuilder()
.withUrl(hubUrl,{
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
})
.build();
var hubStart = hub.start()
.then(function (e) {
$("#notification").data("kendoNotification").success("SignalR Hub Started!");
})
.catch(function (err) {
return console.error(err.toString());
});
});
function onPush(e) {
var notification = $("#notification").data("kendoNotification");
notification.success(e.type);
}