dhtmlxScheduler с ASP.NET MVC
Это руководство описывает процесс создания планировщика с помощью ASP.NET и REST API на серверной стороне.
Если вас интересуют другие серверные интеграции с Scheduler, ознакомьтесь с этими руководствами:
- dhtmlxScheduler с ASP.NET Core
- dhtmlxScheduler с Node.js
- dhtmlxScheduler с PHP
- dhtmlxScheduler с PHP: Slim
- dhtmlxScheduler с PHP:Laravel
- dhtmlxScheduler с SalesForce LWC
- dhtmlxScheduler с Ruby on Rails
- dhtmlxScheduler с dhtmlxConnector
В этом примере мы используем ASP.NET MVC 5 вместе с контроллером Web API для реализации REST API и создания приложения с планировщиком. Для работы с базой данных будет использоваться Entity Framework. Разработка ведётся в среде Visual Studio.
Полный исходный код доступен на GitHub.
Шаг 1. Создание проекта
Запустите Visual Studio 2022 и выберите Create a new project.

Затем выберите "ASP.NET Web Application" и задайте имя DHX.Scheduler.Web. Если шаблон отсутствует, обратитесь к разделу Troubleshooting.


Выберите шаблон "Empty project" и отметьте опции MVC и Web API справа:

Шаг 2. Добавление планировщика на страницу
Создание контроллера
После создания пустого проекта следующим шагом будет добавление MVC-контроллера, который отобразит страницу с планировщиком.
Кликните правой кнопкой мыши по папке Controllers, выберите Add -> Controller. В открывшемся окне выберите MVC 5 Controller -> Empty и нажмите Add. Назовите контроллер "HomeController".

В HomeController уже присутствует метод Index() класса ActionResult, поэтому дополнительная логика не требуется. Нужно лишь добавить представление для этого метода.
using System.Web.Mvc;
namespace DHX.Scheduler.Web.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}
}
Создание представления
Далее создайте страницу index. Перейдите в Views/Home и добавьте пустое представление с именем Index:

Откройте новое представление и вставьте следующий код:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width="device-width"" />
<title>Index</title>
<link href="https://cdn.dhtmlx.com/scheduler/edge/dhtmlxscheduler.css"
rel="stylesheet" type="text/css" />
<script src="https://cdn.dhtmlx.com/scheduler/edge/dhtmlxscheduler.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
// initializing scheduler
scheduler.init("scheduler_here", new Date(2022,0,15));
// initiating data loading
scheduler.load("/api/scheduler");
// initializing dataProcessor
var dp = scheduler.createDataProcessor("/api/scheduler");
// and attaching it to scheduler
dp.init(scheduler);
// setting the REST mode for dataProcessor
dp.setTransactionMode("REST");
});
</script>
</head>
<body>
<div id="scheduler_here" className="dhx_cal_container">
<div className="dhx_cal_navline">
<div className="dhx_cal_prev_button"> </div>
<div className="dhx_cal_next_button"> </div>
<div className="dhx_cal_today_button"></div>
<div className="dhx_cal_date"></div>
<div className="dhx_cal_tab" name="day_tab"></div>
<div className="dhx_cal_tab" name="week_tab"></div>
<div className="dhx_cal_tab" name="month_tab"></div>
</div>
<div className="dhx_cal_header"></div>
<div className="dhx_cal_data"></div>
</div>
</body>
</html>
Что здесь происходит:
- создаётся базовый макет страницы для приложения с планировщиком
- подключаются JS и CSS dhtmlx scheduler через CDN-ссылки
- создаётся сам планировщик на странице
Также планировщик настраивается для работы с RESTful API по адресу "/api/scheduler/" для загрузки данных и как основной маршрут:
scheduler.load("/api/scheduler");
// initializing dataProcessor
var dp = scheduler.createDataProcessor("/api/scheduler");
// and attaching it to scheduler
dp.init(scheduler);
// setting the REST mode for dataProcessor
dp.setTransactionMode("REST");
Реализация серверной части будет рассмотрена далее. Пока что вы можете запустить прило жение и увидеть отображение планировщика.

Шаг 3. Создание моделей и базы данных
Создание моделей
Далее определим классы моделей для планировщика. Вам понадобится класс, описывающий события планировщика. Обратите внимание, что dhtmlxScheduler использует определённые имена свойств в своей модели данных, отличающиеся от стандартного C#-стиля. Некоторые клиентские свойства могут не храниться в базе, но использоваться в логике клиента или сервера.
Чтобы это учесть, мы применим паттерн Data Transfer Object: определим отдельные классы доменной модели для EF и внутреннего использования, а также отдельные DTO-классы для обмена с Web API. Позднее будет настроено сопоставление между этими моделями.
Модель события планировщика
Начнем с создания класса для события. Пример базовой реализации:
using System;
namespace DHX.Scheduler.Web.Models
{
public class SchedulerEvent
{
public int Id { get; set; }
public string Text { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
}
Имейте в виду, что события планировщика могут содержать и другие свойства, расширяющие функциональность календаря. В этом примере приведён минимальный набор.
Настройка подключения к базе данных
Установка Entity Framework
Добавить фреймворк можно через NuGet package manager:

Или выполните команду в Package Manager Console:
PM> Install-Package EntityFramework
Создание контекста базы данных
Создайте класс Context. Он представляет сессию с базой данных и отвечает за получение и сохранение данных.
Кликните правой кнопкой мыши по папке Models, выберите Add -> Class, задайте имя "SchedulerContext" и добавьте следующий код:
using System.Data.Entity;
namespace DHX.Scheduler.Web.Models
{
public class SchedulerContext : DbContext
{
public DbSet<SchedulerEvent> SchedulerEvents { get; set; }
}
}
Добавление начальных записей в базу данных
Теперь добавим несколько тестовых записей.
Entity Framework может автоматически создать базу данных при запуске приложения. Мы хотим, чтобы база удалялась и пересоздавалась при каждом изменении модели.
Для этого создайте инициализатор базы данных - новый класс в App_Start, наследующий DropCreateDatabaseIfModelChanges. Назовём его "SchedulerInitializer".
В этом классе переопределите метод Seed() для наполнения базы тестовыми данными.
Полный класс SchedulerInitializer:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using DHX.Scheduler.Web.Models;
namespace DHX.Scheduler.Web.App_Start
{
public class SchedulerInitializer:DropCreateDatabaseIfModelChanges<SchedulerContext>
{
protected override void Seed(SchedulerContext context)
{
List<SchedulerEvent> events = new List<SchedulerEvent>()
{
new SchedulerEvent()
{
Id = 1,
Text = "Event 1",
StartDate = new DateTime(2022, 1, 11, 2, 0, 0),
EndDate = new DateTime(2022, 1, 11, 4, 0, 0)
},
new SchedulerEvent()
{
Id = 2,
Text = "Event 2",
StartDate = new DateTime(2022, 1, 14, 3, 0, 0),
EndDate = new DateTime(2022, 1, 14, 6, 0, 0)
},
new SchedulerEvent()
{
Id = 3,
Text = "Multiday event",
StartDate = new DateTime(2022, 1, 11, 0, 0, 0),
EndDate = new DateTime(2022, 1, 16, 0, 0, 0)
}
};
events.ForEach(s => context.SchedulerEvents.Add(s));
context.SaveChanges();
}
}
}
Откройте Global.asax. В этом файле размещается код, выполняющийся при старте приложения. Добавьте необходимое пространство имён и установите инициализатор контекста внутри Application_Start():
using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;
using System.Data.Entity;
using DHX.Scheduler.Web.App_Start;
namespace DHX.Scheduler.Web
{
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
Database.SetInitializer(new SchedulerInitializer()); /*!*/
}
}
}
Описание DTO и сопоставление
Теперь определим DTO-классы, которые будет использовать Web API. Для сопоставления между Model и DTO реализуем явные операторы преобразования.
Вот структура класса WebAPIEvent:
using System;
namespace DHX.Scheduler.Web.Models
{
public class WebAPIEvent
{
public int id { get; set; }
public string text { get; set; }
public string start_date { get; set; }
public string end_date { get; set; }
public static explicit operator WebAPIEvent(SchedulerEvent schedulerEvent)
{
return new WebAPIEvent
{
id = schedulerEvent.Id,
text = schedulerEvent.Text,
start_date = schedulerEvent.StartDate.ToString("yyyy-MM-dd HH:mm"),
end_date = schedulerEvent.EndDate.ToString("yyyy-MM-dd HH:mm")
};
}
public static explicit operator SchedulerEvent(WebAPIEvent schedulerEvent)
{
return new SchedulerEvent
{
Id = schedulerEvent.id,
Text = schedulerEvent.text,
StartDate = DateTime.Parse(
schedulerEvent.start_date,
System.Globalization.CultureInfo.InvariantCulture),
EndDate = DateTime.Parse(
schedulerEvent.end_date,
System.Globalization.CultureInfo.InvariantCulture)
};
}
}
}
Шаг 4. Реализация Web API
Контроллер Scheduler
Чтобы добавить новый контроллер:
- Кликните правой кнопкой мыши на папке Controllers и выберите Add -> Controller.
- Выберите Web API 2 Controller -> Empty, з атем введите "SchedulerController" в качестве имени контроллера.
Теперь настроим базовые действия CRUD для управления событиями планировщика:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web.Http;
using DHX.Scheduler.Web.App_Start;
using DHX.Scheduler.Web.Models;
namespace DHX.Scheduler.Web.Controllers
{
public class SchedulerController : ApiController
{
private SchedulerContext db = new SchedulerContext();
// GET: api/scheduler
public IEnumerable<WebAPIEvent> Get()
{
return db.SchedulerEvents
.ToList()
.Select(e => (WebAPIEvent)e);
}
// GET: api/scheduler/5
public WebAPIEvent Get(int id)
{
return (WebAPIEvent)db.SchedulerEvents.Find(id);
}
// PUT: api/scheduler/5
[HttpPut]
public IHttpActionResult EditSchedulerEvent(int id, WebAPIEvent webAPIEvent)
{
var updatedSchedulerEvent = (SchedulerEvent)webAPIEvent;
updatedSchedulerEvent.Id = id;
db.Entry(updatedSchedulerEvent).State = EntityState.Modified;
db.SaveChanges();
return Ok(new
{
action = "updated"
});
}
// POST: api/scheduler/5
[HttpPost]
public IHttpActionResult CreateSchedulerEvent(WebAPIEvent webAPIEvent)
{
var newSchedulerEvent = (SchedulerEvent)webAPIEvent;
db.SchedulerEvents.Add(newSchedulerEvent);
db.SaveChanges();
return Ok(new
{
tid = newSchedulerEvent.Id,
action = "inserted"
});
}
// DELETE: api/scheduler/5
[HttpDelete]
public IHttpActionResult DeleteSchedulerEvent(int id)
{
var schedulerEvent = db.SchedulerEvents.Find(id);
if (schedulerEvent != null)
{
db.SchedulerEvents.Remove(schedulerEvent);
db.SaveChanges();
}
return Ok(new
{
action = "deleted"
});
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
В этом коде:
- События планировщика загружаются из базы данных, а их DTO возвращаются в действиях GET.
- Для действий PUT и POST DTO принимаются на вход, преобразуются обратно в модели SchedulerEvent и изменения сохраняются в контексте базы данных.
С этим набором действий приложение готово к запуску и предоставляет полностью работоспособный планировщик.

Готовый пример доступен на github.
Если Scheduler не отображает события на странице, ознакомьтесь со статьёй Устранение проблем с интеграцией Backend.