Суперлегкий CRUD для ASP.NET Core додатків з бібліотекою EasyData

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Одним із перших завдань для більшості бізнес-додатків є реалізація операцій CRUD (Create, Read, Update, Delete) для основних об’єктів, з якими працює ця програма.

Кожен розробник, якому потрібно вирішити це завдання, стикається з наступними проблемами:

  • Створення CRUD-сторінок та форм є дуже нудним та трудомістким. Повірте, я бував там багато разів.
  • Якщо ви робите це вручну, це може бути дуже повільним та схильним до помилок (пропущені поля, забуті валідатори тощо).
  • Звичайно, ви можете скористатися можливостями scaffolding’у, що їх надає Visual Studio. Але це також буде зовсім не швидкий процес, оскільки його потрібно запускати для кожного класу моделі. У підсумку ви отримуєте багато файлів .cs та .cshtml, які вам потрібно буде відредагувати вручну, якщо щось із поведінки або зовнішнього вигляду за замовчуванням не відповідає вашим потребам. У разі будь-яких змін у класах моделей вам потрібно буде оновити ці згенеровані контролери та сторінки вручну або відновити код та форми для цього класу моделі з нуля.
  • А головне, це рішення все одно не забезпечує деяких важливих, а часом і необхідних функцій, таких як pagination чи пошук.

Рішення: бібліотека EasyData

Для вирішення більшості (якщо не всіх) цих проблем ми створили бібліотеку з відкритим кодом EasyData (розповсюджується за MIT ліцензією). Головною перевагою EasyData є те, що вона використовує декларативний підхід. Весь процес можна розділити на два основні етапи:

  1. Ви «описуєте», з якими даними (сутностями та атрибутами) ви хочете працювати і як саме ваша програма повинна працювати з цими даними (типи, обмеження, відносини між сутностями тощо).
  2. На основі цієї інформації бібліотека EasyData розгортає Web API для CRUD-операцій та інтерфейс користувача на основі чистого (ванільного) JavaScript, що дозволяє вашим користувачам виконувати всі ті операції.

Найдивовижніше тут те, що у випадку використання Entity Framework Core для першого кроку («опису» даних) вам потрібен лише ваш DbContext! Ви просто «подаєте» його до бібліотеки, і EasyData автоматично витягує звідти всю необхідну інформацію для створення кінцевих точок API та інтерфейсу CRUD.

Весь процес займає всього кілька хвилин і близько 10 рядків коду.

Демонстрація

Ось невелике відео, яке демонструє, як працює 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.

Ця сторінка буде «ловити» всі URL-адреси, які починаються з певного префіксу (/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.2/easydata.min.css" />

<div id="EasyDataContainer"></div>

@section Scripts {
    <script src="https://cdn.korzh.com/ed/1.2.2/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), це поки єдиний доступний завантажувач метаданих. У майбутніх версіях можна буде завантажувати метадані безпосередньо з DbConnection або, можливо, в якійсь інший спосіб.

EasyData middleware

EasyData middleware відповідає за обробку REST API для всіх CRUD (і не тільки) операцій, ініційованих веб сторінкою.

Щоб додати middleware у чергу обробки вашого ASP.NET Core додатку використовуйте функцію MapEasyData всередині функції налаштувань UseEndpoints:

  app.UseEndpoints(endpoints =>
    {
       endpoints.MapEasyData(options => {
            options.UseDbContext<AppDbContext>();
        });
    }
Цей виклик слід зробити перед MapMvc абоMapRazorPages.

Стандартний enpoint для EasyData middlware буде /api/easydata, але ви легко можете змінити його на інший:

   endpoints.MapEasyData(options => {
        options.Endpoint = "/api/my-crud";
        .    .    .    .
    });

Єдине, що потрібно налаштувати для EasyData middleware, це «сказати» йому, звідки брати метадані. Наразі доступний лише один варіант: отримання метаданих із DbContext. Ось чому ми додаємо виклик UseDbContext<AppDbContext>() у наведеному вище прикладі. Окрім отримання метаданих, UseDbContext також забезпечує наш middlware всіма засобами для виконання CRUD-операцій (через сам об’єкт DbContext).

Коренева сторінка інтерфейсу EasyData

Це має бути Razor сторінка або MVC view що буде відкриватися для будь-якого шляху, який починається з префіксу /easydata/ (тому всі шляхи, такі як /easydata/student або /easydata/invoice, повинні бути оброблені цією сторінкою).

NB: /easydata — префікс за замовчуванням. Ви можете встановити і інший шлях до цієї сторінки, але в цьому випадку його потрібно буде вказати в параметрах нашого об’єкта RootDispatcherView

Наша корнева («catch-all») сторінка може містити будь-які елементи HTML на ваш вибір. Але для забезбечення візуалізації та нормальної роботи CRUD, вона має включати наступні 4 елемента:

  • <link> element з посиланням на CSS файл EasyData (easydata.min.cs)
  • Контейнер (порожній елемент div), де буде відображатися наш інтерфейс. За замовчуванням він повинен мати ідентифікатор EasyDataContainer, але це також можна налаштувати за допомогою опцій.
  • <script> елемент з посиланням на файл easydata.min.js.
  • Та невеликий скрипт, що створює та запускає об’єкт EasyDataViewDispatcher при завантаженні сторінки.

Приклад найпростішої корневої сторінки ви можете побачити у розділі «Початок роботи» вище.

На завершення

На разі 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), коли вже є деяке розуміння з якими даними доведеться працювати, але не хочеться витрачати багато часу на реалізацію найпростіших операцій з тими даними.

Звісно, ми сподіваємось що з часом можна буде повноцінно використовувати це рішення і у production середовищі. Будемо раді будь-яким вашим зауваженням чи порадам з цього приводу.

Ну і звісно, не забудьте поставити зірочку в EasyData репозиторії на GitHub особливо якщо ця бібліотека допомогла зекономити вам трохи часу.

👍НравитсяПонравилось14
В избранноеВ избранном5
LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Круто! спасибо за статью. Попробую заюзать на пет-проекте в качестве быстрой админки) а вы не знаете как настроить, чтоб он умел работал с полями byte[] ? При дефолтной настройке он их просто игнорирует и не видит в базе.

Не думав, що хтось ще використовує ASP.NET

Та я просто останній раз з ним працював десь року 2006.
Мені здавалося, що зараз всі переходять на JavaScript front-end + REST API

Ну там все действия внутри EasyData AJAX, но само приложение не SPA.
Я бе не сказал, что SPA эффективно вот всегда,
при чём тут тот ASP.NET из 2006 года, вообще не ясно.

Если 2006 год, то это web forms, которые официально deprecated
Про хтось выкористовует смотри количество вакансий.

ASP.NET — все же фреймворк (как и ASP. NET Core), и он в себя включает
1. UI — MVC + Razor Pages
2. WebApi — REST
3. SignalR — realtime notificaitons
4. SPA поддержку — когда ты можешь захостить апи и SPA под одним доменом и ASP.Net локально будет еще запускать npm start и мапить все запросы со статиков в папке SPA, и плюс отдельно обрабатывать WebApi запросы

поэтому вопрос тут не корректен, так как даже с SPA — все равно нужен API, а это WebApi, который является частью ASP.NET-а

ну и плюс задачи разные бывают, если это аля онлайн магазин, то EasyData вполне подойдет для админки, которой будет пользоваться пару человек и не нужно туда лепить SPA.
если провести параллели, то ваш вопрос звучит как — «не думал что кто-то еще использует Spring, так как я его использовал в 2006 году и сейчас все используют SPA»

По-перше, мова про ASP.NET Core. Це зовсім не те саме що старий ASP.NET.
По-друге, і на ASP.NET Core і навіть на старом ASP.NET як раз і роблять саме те, про що ви кажете. Дуже часто це якийсь SPA на фронтеде (Angular, React, Vue) і REST API на backend’і (зроблений, власне, засобами ASP.NET Core).
Але для відносно невеликих проектів та рішень, що не потребують якогось супер складного інтерфейсу (а просто є набором форм), цілком нормально зробити класичний веб-додаток на тих самих Razor Pages чи MVC.

Подписаться на комментарии