Одной из первых задач для большинства бизнес-приложений на ASP.NET Core является реализация операций CRUD (Create, Read, Update, Delete) для основных объектов, с которыми работает ваше решение.
Каждый разработчик, которому нужно решить эту задачу, знает, что создание CRUD-страниц и форм — очень скучный и трудоемкий процесс.
Если делать это вручную, то получится очень медленно и наверняка с кучей недоработок (пропущенные поля, забытые валидаторы и т.д.).
Можно воспользоваться инструментом scaffolding'а, доступным в Visual Studio. Но даже в этом случае это будет совсем не быстрый процесс, поскольку его нужно запускать для каждого класса модели. В итоге вы получаете множество .cs/.cshtml файлов, которые нужно поддерживать и атуализировать по мере изменений в классах модели или просто когда нужно что-то исправить в поведении или внешнем виде CRUD страниц. Если количество сущностей в вашей БД превышает десяток, то весьма велики шансы того, что файлы для реализации CRUD операций занимают больше 50% всей кодовой базы вашего проекта. Более того это решение все равно не обеспечивает некоторых важных, а порой и необходимых функций, таких как разбитие на страницы в режиме просмотра (pagination) или банальные поиск/фильтрация.
Решение: использовать библиотеку с открытым кодом EasyData, о которой и пойдет речь в данной статье.
Что такое EasyData?
EasyData и была создана для решения большинства (если не всех) проблем описанных выше. Это библиотека с открытым кодом, распространяется по MIT лицензии, исходники доступны на GitHub. Главной особенностью является использование декларативного подхода.
Весь процесс можно разделить на два основных этапа:
- Вы «описываете», с какими данными (сущностями и атрибутами) вы хотите работать и как ваша программа должна работать с этими данными (типы, ограничения, отношения между сущностями и т.д.).
- На основе этой информации библиотека EasyData разворачивает Web API для CRUD-операций и пользовательский интерфейс на основе чистого (ванильного) JavaScript, что позволяет вашим пользователям выполнять все те операции.
Самое замачательное здесь то, что в случае использования Entity Framework Core для первого шага («описания» данных) вам нужен только ваш DbContext! Вы просто «скармливаете» его библиотеке, и EasyData автоматически извлекает оттуда всю необходимую информацию для разворачивания CRUD API и пользовательского интерфейса.
Весь процесс занимает всего несколько минут и около 10 строк кода. Демонстрацию можна увидеть в небольшом git ролике вначале статьи.
Подключаем EasyData в свой проект
Прежде всего, чтобы попробовать EasyData в работе, вы можете открыть и запустить один из примеров проектов, доступных на GitHub.
Для установки EasyData в собственный проект надо выполнить следующие 3 простых шага:
1. Устанавливаем NuGet пакеты EasyData
- EasyData.AspNetCore
- EasyData.EntityFrameworkCore.Relational
2. Добавляем EasyData middleware в Startup.Configure
:
using EasyData.Services;
. . . . .
app.UseEndpoints(endpoints => {
endpoints.MapEasyData(options => {
options.UseDbContext<AppDbContext>();
});
endpoints.MapRazorPages();
});
В опциях нашего middleware мы указываем класс объекта DbContext, который и будет использоваться как источник метаданных.
3. Настраиваем страницу CRUD операций
Если вы используете Razor Pages, добавьте новую страницу (например, EasyData.chstml). Если это MVC, вам понадобятся новый контроллер и соответствующий ему view.
Наша новая страница должна будет «ловить» все адреса, которые начинаются с определенного префикса (/easydata/
по умолчанию, но это можно настроить). Для этого мы используем специальный catch-all параметр в определении маршрута: "/easydata/{**entity}"
.
Кроме того, мы также добавляем .css и .js файлы EasyData (easydata.min.css
и easydata.min.js
), которые обеспечивают отрисовку интерфейса управления данными и обработку всех CRUD-операций на стороне клиента.
@page "/easydata/{**entity}"
@{
ViewData["Title"] = "EasyData";
}
<link rel="stylesheet" href="https://cdn.korzh.com/ed/1.2.4/easydata.min.css" />
<div id="EasyDataContainer"></div>
@section Scripts {
<script src="https://cdn.korzh.com/ed/1.2.4/easydata.min.js" type="text/javascript"></script>
<script>
window.addEventListener('load', function () {
new easydata.crud.EasyDataViewDispatcher().run()
});
</script>
}
Вот и все. Теперь вы можете запустить свой проект, открыть URL-адрес /easydata
и наслаждаться функциями CRUD.
Вот как это выглядит в итоге:
Страница просмотра значений для некоторой сущности (в данном случае, Orders)
Диалог редактирования одной записи
Lookup диалог, который был открыт из диалога редактирования записи
Как это работает
Коротко о том, как работает вся эта магия.
Как мы уже упоминали ранее, EasyData решает 3 основных задачи:
- Собирает метаданные из нашей базы данных.
- Устанавливает API для основных CRUD операций.
- Визуализирует интерфейс (опять же, на основе метаданных) и обрабатывает все взаимодействие пользователя с этим интерфейсом.
Давайте изучим все эти части более подробно.
Метаданные
Метаданные это данные о ваших данных: какие сущности (таблицы) хранятся в вашей базе данных, как они связаны, какие имеют атрибуты (поля) и другая полезная информация.
EasyData собирает метаданные (каким-либо способом — об этом см. ниже) и сохраняет их в объекте класса MetaData. Этот объект содержит список сущностей (таблиц), атрибуты (поля) для каждой сущности, связи между сущностями и некоторую дополнительную информацию, используемую в API и при визуализации и обработке пользовательского интерфейса.
Для заполнения объекта MetaData нам нужно указать некоторый загрузчик метаданных. В нашем примере мы сделали это с помощью вызова UseDbContext
для загрузки метаданных из объекта DbConext
. На данный момент (в версии 1.2), это пока единственный доступный загрузчик метаданных. В будущих версиях можно будет загружать метаданные непосредственно с БД или, возможно, каким-нибудь другим способом.
EasyData middleware
EasyData middleware отвечает за обработку REST API для всех CRUD (и не только) операций, инициированных веб страницей.
Чтобы добавить middleware в очередь обработки вашего ASP.NET Core приложения используйте функцию MapEasyData
в процессе настроки точек вызова (endpoints) UseEndpoints
:
app.UseEndpoints(endpoints =>
{
endpoints.MapEasyData(options => {
options.UseDbContext<AppDbContext>();
});
}
Этот вызов желательно поставить перед любым вызовом MapControllerRoute
или MapRazorPages
.
По умолчанию EasyData API будет откликаться по адресу /api/easydata
, но вы легко можете изменить его на другой:
endpoints.MapEasyData(options => {
options.Endpoint = "/api/my-crud";
. . . .
});
Единственное, что нужно настроить для EasyData middleware, это «сказать» ему, откуда брать метаданные. Как уже упоминалось выше, сейчас доступен только один вариант, а именно получение метаданных с DbContext. Вот почему мы добавляем вызов UseDbContext <AppDbContext>()
в приведенном выше примере. Кроме получения метаданных, UseDbContext
также обеспечивает наш middlware всеми средствами для выполнения CRUD-операций (через сам объект DbContext
).
Корневая страница интерфейса EasyData
В качестве такой страницы выступает Razor page или же MVC view. Эта страница должна обрабатывать все URL адреса, которые начинается с определенного префикса. По умолчанию это /easydata/
и поэтому все пути, типа /easydata/student
или /easydata/invoice
, должны быть обработаны этой страницей.
NB: /easydata/
— префикс по умолчанию. Вы можете установить и другой путь к этой странице, но в этом случае его нужно будет указать в параметрах нашего объекта RootDispatcherView
Наша корневая страница может содержать любые элементы HTML на ваш выбор. Но для нормальной работы CRUD интерфейса, она должна включать следующие 4 элемента:
<link>
элемент со ссылкой на CSS файл EasyData (easydata.min.cs
)
Контейнер (пустой элемент
div
), где будет рисоваться наш CRUD интерфейс. По умолчанию он должен иметь идентификаторEasyDataContainer
, но это также можно настроить с помощью опций.
<script>
элемент со ссылкой на файлeasydata.min.js
.
небольшой скрипт, который создает и запускает объект
EasyDataViewDispatcher
при загрузке страницы.
Пример простейшей корневой страницы вы можете увидеть в разделе «Подключаем EasyData в свой проект» выше.
В завершение
На данный момент EasyData может работать с .NET Core 3.1 и .NET 5. Очевидно, поддерживаются все версии ASP.NET Core и Entity Framework Core, которые могут работать с указанными версиями .NET (Core).
Однако не будет большой проблемы при необходимости добавить также поддержку предыдущих версий .NET Core или даже .NET Framework 4.x. Если кому-то это нужно, создавайте новый issue про это в GitHub репозитории библиотеки.
EasyData был сделан, в первую очередь, для быстрого создания прототипов новых проектов или так называемых POC (proof of concept), когда уже есть некоторое понимание с какими данными придется работать, но не хочется тратить много времени на реализацию простейших операций с этими данными.
Конечно, мы надеемся, что со временем можно будет полноценно использовать это решение и для вполне себе рабочих решений (не только прототипов). Будем рады любым вашим замечаниям или советам по этому поводу.
Ну и конечно, не забудьте поставить звездочку в EasyData репозитории на GitHub. Особенно если эта библиотека помогла сэкономить вам немного времени.
sashaeve
Отличная библиотека, спасибо!
Вопрос: планируется ли поддержка Fluent API вместо атрибутов?
korzh Автор
Да, планируется. Добавил про это issue на GitHub
Как набереться какое-то количество голосов, обязательно сделаем.