Несколько лет назад я реализовал ряд проектов, для управления которыми использовалась система управления основанная на ASP.NET Dynamic Data. В свое время эта система сэкономила достаточно много времени и ресурсов. Но как известно, в ИТ все развивается очень стремительно. Не так давно вышла в релиз платформа .NET Core, основным нововведением которой была поддержка кроссплатформенности. Это в свою очередь позволило мне мигрировать ряд небольших проектов, а также проектов, которые я поддерживаю на некоммерческой основе на бюджетные сервера от Digital Ocean, которые, как известно, поддерживают только ОС семейства Linux. Когда дело дошло до системы управления передо мной стоял выбор — с минимальным изменением кода портировать проект под Mono, или переписать с нуля использую новые возможности .NET Core. Взвесив все за и против, я выбрал второй вариант. Что из этого вышло и что я собираюсь получить вы можете узнать под катом.

Для для тех кто не в курсе, что такое скаффолдинг, краткое описание этого подхода:
Вдохновившись примером Ruby on Rail в 2007 году компания Майкрософт разработала свой инструмент для быстрого проектирования веб-приложения работающих с данными.
И сам подход и инструмент ASP.NET Dynamic Data мне понравились. Причем на столько, что как я уже писал выше, я создал свою систему на их основе. Однако, за время использования этого решения у меня появляли различные идеи о том, как можно было бы улучшить этот продукт. И так, к тому, чтобы переписать проект с нуля меня подтолкнул ряд недостатков решения на базе ASP.NET Dynamic Data, среди которых основные:
Исходя из этих недостатков я выделил для себя ряд возможностей, которые я бы хотел реализовать в новом проекте:
На данный момент уже написана основная часть кода, которая позволяет работать с данными несложных по структуре баз.
Процедура работы следующая:


В планах также реализация интеграции с хранилищем Amazon S3.
Хочу выразить благодарность gelas за помощь в работе над проектом и здравую критику.
Отдельно хочу отметить, что проект создавался мною в рамках комьюнити украинских разработчиков .NET Core — .NET Core Ukrainian User Group. На данный момент наибольшая активность участников наблюдается в группе в Facebook, но и группу в ВК мы также планируем наполнять. Если у вас есть вопросы по .NET Core, идеи которыми вы хотите поделиться, или вы только присматриваетесь к этой технологии – присоединяйтесь, будет интересно!
Проект доступен под лицензией MIT на GitHub.
1. Руководство по ASP.NET Dynamic Data.
2. Википедия. Скаффолдинг.

Для для тех кто не в курсе, что такое скаффолдинг, краткое описание этого подхода:
"Скаффолдинг — это метод метапрограммирования для создания веб-приложений, взаимодействующих с базой данных. Этот метод поддерживается некоторыми современными MVC-фреймворками (Grails, Yii, Ruby on Rails, Django, CakePHP, Phalcon PHP, Symfony, ASP.NET Dynamic Data и другими.). Разработчик в них задает спецификации, по которым в дальнейшем генерируется программный код для операций создания определенных записей в базе данных, их чтения, обновления и удаления."[1]
Вдохновившись примером Ruby on Rail в 2007 году компания Майкрософт разработала свой инструмент для быстрого проектирования веб-приложения работающих с данными.
"ASP.NET Dynamic Data – это фреймворк, который позволяет быстро разрабатывать полнофункциональные data-driven приложения, используя LINQ to SQL или Entity Framework, а также расширяет возможности элементов управления DetailsView, FormView, GridView и ListView в плане функциональности, проверки данных и отображения.
Если говорить по простому, то Dynamic Data предназначен для быстрой генерации фронт-эндов для баз данных Microsoft SQL Server."[2]
И сам подход и инструмент ASP.NET Dynamic Data мне понравились. Причем на столько, что как я уже писал выше, я создал свою систему на их основе. Однако, за время использования этого решения у меня появляли различные идеи о том, как можно было бы улучшить этот продукт. И так, к тому, чтобы переписать проект с нуля меня подтолкнул ряд недостатков решения на базе ASP.NET Dynamic Data, среди которых основные:
- Построение модели не напрямую из базы данных, а по сгенерированной модели Entity Framework, что в свою очередь влечет необходимость переброски проекта, содержащего модель в случае изменения структуры базы.
- Проект был основан на устаревшей на сегодняшний день технологии WebForms
- Поддерживался только SQL Server
Исходя из этих недостатков я выделил для себя ряд возможностей, которые я бы хотел реализовать в новом проекте:
- Поддержка кроссплатформенности
- Поддержка различных баз данных (на данный момент реализована поддержка SQL Server и идет работа над реализацией поддержки MySQL. В планах также: PostgreSQL, Oracle Database, SQLite).
- Генерация модели базы данных напрямую из базы.
- Lookup с расширенными возможностями поиска
Общий принцип работы системы
На данный момент уже написана основная часть кода, которая позволяет работать с данными несложных по структуре баз.
Процедура работы следующая:
- Для базы данных создается рабочая директория, которая указывается в базовом файле конфигурации приложения.
- В этой директории создается файл с информацией о параметрах подключения к базе и параметрах подключения к файловому хранилищу, а также конфигурируются учетные записи пользователей системы.
- Далее, после первого запуска системы, пользователь переходит в раздел Administration и запускает процесс построения модели базы данных, которая будет сохранена в рабочую директорию в файл db.json.
- После того, как модель построена, в принципе, с системой можно уже работать. Однако для полностью комфортной работы может понадобиться уточнить параметры некоторых полей. Чтобы упростить процедуру поддержки конфигурационного файла в будущем, я предусмотрел возможность описывать уточненную конфигурацию в отдельном файле db_ex.json. Это файл по структуре аналогичен db.json, но в нем необходимо указывать только имя поля, которое требует дополнительной настройки и указать те параметры, которые отличаются от сгенерированных по умолчанию. Разбиение конфигурации на два отельных файла позволяет не беспокоиться о том, что если в будущем придется обновить модель данных то все кастомные настройки будут потеряны. А это может произойти, например, если в таблицу были добавлены новые поля, или была создана новая таблица в базе.

Конфигурация
- db.json – файл с описанием схемын базы данных
- db_ex.json – файл с расширенным описания схемы. Позволяет переопределять типы полей и другую мета-информацию.
- configuration.json – файл содержащий информацию о подключении к базе данных, пользователям системы и информацию для подключения к файловым хранилищам

Структура описания базы
На данный момент в системе предусмотрены (но еще не все реализованы) следующие редакторы для различных типов полей:
Схема
- Name – системное название схемы.
- Title – заголовок. Отображается в интерфейсе системы
- Tables – список таблиц
Таблица
- ShowInList – параметр указывает, будет ли отображаться таблица в навигационном меню
- Name – системное имя таблицы. Соответствует имени таблицы в базе данных.
- Title – заголовок таблицы. Оторажется в навигационном меню и на странице редактирования таблицы.
- Description – описание. Отображается на странице редактирования таблицы
- Columns – список полей
Поле
- Position – позиция поля в гриде и редакторе.
- IsKey – является ли поле ключевым полем в базе данных
- IsNullable – допустимы ли NULL-значения в поле
- Reference – ...
- ShowInGrid – отображать, или не поле в гриде
- AutoIncrement – является ли поле автоинкрементным
- MaxValue – максимальное значение поля
- MinValue – максимальное значение поля
- MaxLength – максимальная длинна поля
- Readonly – является ли поле доступным только для чтения
- Type – тип поля
- Name – системное название поля, соответствует имени поля в таблице базы данных
- Title – название поля, тображается в редакторе и гриде
- Description – описание поля
Поддержка типов данных
На данный момент в системе предусмотрены (но еще не все реализованы) следующие редакторы для различных типов полей:
- Text — обычное текстовое поле
- Email — поле для ввода почтового адреса
- Url — поле для ввода url
- Phone — поле для ввода телефона
- HTML — поле содержащее полноценный WYSIWYG редактор.
- Password — поле для ввода пароля
- Date — поле для ввода даты
- Time — поле для ввода времени
- DateTime — поле для ввода времени и даты
- File — поле для загрузки файла и сохранения идентификатора загруженного файла в таблицу
- Integer — поле для ввода целых чисел
- Double — поле для ввода дробных чисел
- Image — поле для загрузки изображения, предпросмотра загруженного изображения и сохранения идентификатора загруженного изображения в таблицу
- Binary — поле для загрузки файла и сохранения содержимого в таблицу,
- Reference — выпадающий список, или всплывающее окно с возможностью поиска для выбора связанного значения
- Boolean — чекбокс
Пример файла конфигурации db.json
{ "Tables": [ { "Columns": [ { "Position": 1, "IsKey": true, "IsNullable": false, "Reference": null, "ShowInGrid": false, "AutoIncrement": true, "MaxValue": null, "MinValue": null, "MaxLength": null, "Readonly": true, "Type": 40, "Name": "Id", "Title": "Id", "Description": "" }, { "Position": 2, "IsKey": true, "IsNullable": false, "Reference": null, "ShowInGrid": false, "AutoIncrement": true, "MaxValue": null, "MinValue": null, "MaxLength": null, "Readonly": true, "Type": 40, "Name": "Name", "Title": "Name", "Description": "" }, { "Position": 3, "IsKey": true, "IsNullable": false, "Reference": null, "ShowInGrid": false, "AutoIncrement": true, "MaxValue": null, "MinValue": null, "MaxLength": null, "Readonly": true, "Type": 40, "Name": "Value", "Title": "Value", "Description": "" } ], "ShowInList": false, "Name": "Setting", "Title": "Настройки", "Description": "Системные настройки" } ], "Generated": "2016-09-27T00:40:48.9189786+03:00", "ExtendedConfigurationLoaded": false, "Name": "Database", "Title": "Database" }
Пример файла конфигурации db_ex.json
{ "Tables": [ { "Columns": [ { "Type": 40, "ShowInGrid": false, "AutoIncrement": true, "Readonly": true, "Name": "Id", "Title": "Системный идентификатор" }, { "Type": 10, "Name": "Name", "Title": "Название" }, { "Type": 10, "Name": "Value", "Title": "Значение" } ], "ShowInList": false, "Name": "Setting", "Title": "Настройки", "Description": "Системные настройки" } ], "Name": "Описание проекта", "Title": "База данных" }
Пример файла конфигурации configuration.json
{ "ConnectionString": "Server=...;Database=...;User Id=...;Password=..;", "SecretKey": "secret-key-123", "ApplicationRestartCommand": "", "StorageConfiguration": { "Type": 0, "Url": "http://static.exapmle.com/user_upload/", "Connection": { "Path": "/var/www/example.com/user_upload/" } }, "Users": [{ "Login": "admin", "Password": "admin", "Administrator": true } ] }
Файловые хранилища
- FileSystem – наиболее частый вариант, когда файловое хранилище располагается на том же сервере, где запущена система управления. В этом случае указаывается путь к файлу.
- FTP – файловое хранилище располагается на удаленном сервере, загрузка файлов происходит по протоколу FTP(реализация в планах)
- AzureStorage – файловое хранилище располагается в Microsoft Azure, загрузка файлов производится в Azure Blob Storage (реализация в планах)
- SSH – файловое хранилище располагается на удаленном сервере, загрузка файлов производится по SSH-протоколу (реализация в планах)
В планах также реализация интеграции с хранилищем Amazon S3.
Послесловие
Хочу выразить благодарность gelas за помощь в работе над проектом и здравую критику.
Отдельно хочу отметить, что проект создавался мною в рамках комьюнити украинских разработчиков .NET Core — .NET Core Ukrainian User Group. На данный момент наибольшая активность участников наблюдается в группе в Facebook, но и группу в ВК мы также планируем наполнять. Если у вас есть вопросы по .NET Core, идеи которыми вы хотите поделиться, или вы только присматриваетесь к этой технологии – присоединяйтесь, будет интересно!
Проект доступен под лицензией MIT на GitHub.
1. Руководство по ASP.NET Dynamic Data.
2. Википедия. Скаффолдинг.