Your search did not match any results.

SignalR Service

Documentation

This demo shows how two users can edit data in the Scheduler simultaneously. A SignalR service is used to broadcast push notifications.

Each Scheduler has an individual store to emulate the situation when Schedulers are being edited on two different clients. Changes made in one Scheduler are repeated in the other and persist until the browser session has expired.

<div class="schedulers"> @for(int i = 1; i <= 2; i++) { <div class="column-@i"> @(Html.DevExtreme().Scheduler() .ID(string.Format("{0}{1}", "scheduler", i)) .DataSource(d => d.Mvc() .Controller("SchedulerSignalR") .Key("AppointmentId") .LoadAction("Get") .UpdateAction("Put") .InsertAction("Post") .DeleteAction("Delete") ) .TimeZone("America/Los_Angeles") .RemoteFiltering(true) .Views(new[] { SchedulerViewType.Day, SchedulerViewType.WorkWeek }) .CurrentView(SchedulerViewType.Day) .CurrentDate(new DateTime(2021, 5, 25)) .StartDayHour(9) .EndDayHour(19) .Height(600) .DateSerializationFormat("yyyy-MM-ddTHH:mm:ssZ") .TextExpr("Text") .DescriptionExpr("Description") .StartDateExpr("StartDate") .EndDateExpr("EndDate") .AllDayExpr("AllDay") .RecurrenceRuleExpr("RecurrenceRule") ) </div> } </div> <script src="~/signalr/signalr-session-id.js"></script> <script src="~/signalr/signalr-client.js"></script> <script> var connection = new signalR.HubConnectionBuilder() .withUrl("@Url.Content("~/schedulerSignalRHub")", { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets }) .configureLogging(signalR.LogLevel.Information) .build(); $(function () { var store1 = $("#scheduler1").dxScheduler("getDataSource").store(); var store2 = $("#scheduler2").dxScheduler("getDataSource").store(); connection.start() .then(function () { connection.on("update", function (key, data) { store1.push([{ type: "update", key: key, data: data }]); store2.push([{ type: "update", key: key, data: data }]); }); connection.on("insert", function (data) { store1.push([{ type: "insert", data: data }]); store2.push([{ type: "insert", data: data }]); }); connection.on("remove", function (key) { store1.push([{ type: "remove", key: key }]); store2.push([{ type: "remove", key: key }]); }); }); }); </script>
using DevExtreme.NETCore.Demos.Models.SampleData; using DevExtreme.NETCore.Demos.ViewModels; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; namespace DevExtreme.NETCore.Demos.Controllers { public class SchedulerController : Controller { public ActionResult SignalRService() { return View(); } } }
using System; using System.Linq; using DevExtreme.AspNet.Data; using DevExtreme.AspNet.Mvc; using DevExtreme.NETCore.Demos.Hubs; using DevExtreme.NETCore.Demos.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; namespace DevExtreme.NETCore.Demos.Controllers.ApiControllers { [Route("api/[controller]")] public class SchedulerSignalRController : Controller { InMemoryAppointmentsDataContext _data; private static readonly Random random = new Random(); private IHubContext<SchedulerSignalRHub> hubContext; public SchedulerSignalRController(IHttpContextAccessor httpContextAccessor, IMemoryCache memoryCache, IHubContext<SchedulerSignalRHub> hubcontext) { _data = new InMemoryAppointmentsDataContext(httpContextAccessor, memoryCache); hubContext = hubcontext; } [HttpGet] public object Get(DataSourceLoadOptions loadOptions) { return DataSourceLoader.Load(_data.Appointments, loadOptions); } [HttpPost] public IActionResult Post(string values) { var newAppointment = new Appointment(); JsonConvert.PopulateObject(values, newAppointment); if(!TryValidateModel(newAppointment)) return BadRequest(ModelState.GetFullErrorMessage()); _data.Appointments.Add(newAppointment); _data.SaveChanges(); var groupName = GetGroupName(); if(groupName != null) { hubContext.Clients.Group(GetGroupName()).SendAsync("insert", newAppointment); } return Ok(); } [HttpPut] public IActionResult Put(int key, string values) { var appointment = _data.Appointments.First(a => a.AppointmentId == key); JsonConvert.PopulateObject(values, appointment); if(!TryValidateModel(appointment)) return BadRequest(ModelState.GetFullErrorMessage()); _data.SaveChanges(); var groupName = GetGroupName(); if(groupName != null) { hubContext.Clients.Group(GetGroupName()).SendAsync("update", key, appointment); } return Ok(); } [HttpDelete] public void Delete(int key) { var appointment = _data.Appointments.First(a => a.AppointmentId == key); _data.Appointments.Remove(appointment); _data.SaveChanges(); var groupName = GetGroupName(); if(groupName != null) { hubContext.Clients.Group(GetGroupName()).SendAsync("remove", key); } } string GetGroupName() { HttpContext.Request.Cookies.TryGetValue(SchedulerSignalRHub.GroupIdKey, out var cookie); return cookie; } } }
using System; using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; namespace DevExtreme.NETCore.Demos.Models { public class Appointment { [JsonProperty(PropertyName = "AppointmentId")] public int AppointmentId { get; set; } [JsonProperty(PropertyName = "Text")] public string Text { get; set; } [JsonProperty(PropertyName = "Description")] public string Description { get; set; } [JsonProperty(PropertyName = "StartDate")] public string StartDate { get; set; } [JsonProperty(PropertyName = "EndDate")] public string EndDate { get; set; } [JsonProperty(PropertyName = "AllDay")] public bool AllDay { get; set; } [JsonProperty(PropertyName = "RecurrenceRule")] public string RecurrenceRule { get; set; } [JsonProperty(PropertyName = "RecurrenceException")] public string RecurrenceException { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; namespace DevExtreme.NETCore.Demos.Models.SampleData { public partial class SampleData { public static readonly IEnumerable<Appointment> Appointments = new[] { new Appointment { AppointmentId = 1, Text = "Website Re-Design Plan", StartDate = "2021-05-24T16:30:00.000Z", EndDate = "2021-05-24T18:30:00.000Z" }, new Appointment { AppointmentId = 2, Text = "Book Flights to San Fran for Sales Trip", StartDate = "2021-05-24T19:00:00.000Z", EndDate = "2021-05-24T20:00:00.000Z", AllDay = true }, new Appointment { AppointmentId = 3, Text = "Install New Router in Dev Room", StartDate = "2021-05-24T21:30:00.000Z", EndDate = "2021-05-24T22:30:00.000Z" }, new Appointment { AppointmentId = 4, Text = "Approve Personal Computer Upgrade Plan", StartDate = "2021-05-25T17:00:00.000Z", EndDate = "2021-05-25T18:00:00.000Z" }, new Appointment { AppointmentId = 5, Text = "Final Budget Review", StartDate = "2021-05-25T19:00:00.000Z", EndDate = "2021-05-25T20:35:00.000Z" }, new Appointment { AppointmentId = 6, Text = "New Brochures", StartDate = "2021-05-25T21:30:00.000Z", EndDate = "2021-05-25T22:45:00.000Z" }, new Appointment { AppointmentId = 7, Text = "Install New Database", StartDate = "2021-05-26T16:45:00.000Z", EndDate = "2021-05-26T18:15:00.000Z" }, new Appointment { AppointmentId = 8, Text = "Approve New Online Marketing Strategy", StartDate = "2021-05-26T19:00:00.000Z", EndDate = "2021-05-26T21:00:00.000Z" }, new Appointment { AppointmentId = 9, Text = "Upgrade Personal Computers", StartDate = "2021-05-26T22:15:00.000Z", EndDate = "2021-05-26T23:30:00.000Z" }, new Appointment { AppointmentId = 10, Text = "Customer Workshop", StartDate = "2021-05-27T18:00:00.000Z", EndDate = "2021-05-27T19:00:00.000Z", AllDay = true }, new Appointment { AppointmentId = 11, Text = "Prepare 2021 Marketing Plan", StartDate = "2021-05-27T18:00:00.000Z", EndDate = "2021-05-27T20:30:00.000Z" }, new Appointment { AppointmentId = 12, Text = "Brochure Design Review", StartDate = "2021-05-27T21:00:00.000Z", EndDate = "2021-05-27T22:30:00.000Z" }, new Appointment { AppointmentId = 13, Text = "Create Icons for Website", StartDate = "2021-05-28T17:00:00.000Z", EndDate = "2021-05-28T18:30:00.000Z" }, new Appointment { AppointmentId = 14, Text = "Upgrade Server Hardware", StartDate = "2021-05-28T21:30:00.000Z", EndDate = "2021-05-28T23:00:00.000Z" }, new Appointment { AppointmentId = 15, Text = "Submit New Website Design", StartDate = "2021-05-28T23:30:00.000Z", EndDate = "2021-05-29T01:00:00.000Z" }, new Appointment { AppointmentId = 16, Text = "Launch New Website", StartDate = "2021-05-28T19:20:00.000Z", EndDate = "2021-05-28T21:00:00.000Z" } }; } }
using System; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; namespace DevExtreme.NETCore.Demos.Hubs { public class SchedulerSignalRHub : Hub { public static string GroupIdKey = "dx-SchedulerSignalRHub-groupId"; public override Task OnConnectedAsync() { string groupId; Context.GetHttpContext().Request.Cookies.TryGetValue(GroupIdKey, out groupId); Groups.AddToGroupAsync(Context.ConnectionId, groupId); return base.OnConnectedAsync(); } } }
.schedulers { display: flex; } .column-1 { padding-right: 5px; } .column-2 { padding-left: 5px; } .dx-scheduler-small .dx-scheduler-view-switcher.dx-tabs { display: table; }