Универсальная система управления данными на базе технологий скаффолдинга и платформы .NET Core

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



    Для для тех кто не в курсе, что такое скаффолдинг, краткое описание этого подхода:
    "Скаффолдинг — это метод метапрограммирования для создания веб-приложений, взаимодействующих с базой данных. Этот метод поддерживается некоторыми современными 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 с расширенными возможностями поиска

    Общий принцип работы системы


    На данный момент уже написана основная часть кода, которая позволяет работать с данными несложных по структуре баз.

    Процедура работы следующая:

    1. Для базы данных создается рабочая директория, которая указывается в базовом файле конфигурации приложения.

    2. В этой директории создается файл с информацией о параметрах подключения к базе и параметрах подключения к файловому хранилищу, а также конфигурируются учетные записи пользователей системы.

    3. Далее, после первого запуска системы, пользователь переходит в раздел Administration и запускает процесс построения модели базы данных, которая будет сохранена в рабочую директорию в файл db.json.

    4. После того, как модель построена, в принципе, с системой можно уже работать. Однако для полностью комфортной работы может понадобиться уточнить параметры некоторых полей. Чтобы упростить процедуру поддержки конфигурационного файла в будущем, я предусмотрел возможность описывать уточненную конфигурацию в отдельном файле 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. Википедия. Скаффолдинг.
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 11

      0
      Упаковать бы это в nuget пакет и сделать каталог examples с примерами, так можно жить первое время без документации
        0

        Эта публикация как раз и была первым шагом к написанию документации. Изначально проект делался под свои личные нужды, но позже я принял решения вынести его open source.

          +1
          Безусловно проект крутой, просто всегда когда использую что-то обычно смотрю каталог с примерами, где создается впечатление о возможностях той или иной либы и её удобстве.
            0

            Постараюсь в ближайшее время сделать примеры! Если будет желание — присоединяйтесь к разработке :)

              0
              на Angular2 для front-end не планируете переходить?

              Когда будет время — надо будет посмотреть проект и может что реализовать :)
                0

                Есть очень большое желание попробовать Angular 2, только к сожалению, времени на это нет :( Базовую версию редактора я сделал на первой версии Angular, а сейчас вместе с gelas разрабатываем более продвинутый UI на react: https://github.com/dncuug/scaffolder-ui

                  0
                  то есть можно не ждать Angular2 :) если уж на react пересели.
                    0

                    Скорее всего, что нет. Но это не точно :) На самом деле UI может быть написан на чем угодно — это может быть даже мобильное, или декстопное приложение. REST API позволяет реализовать такую интеграцию. Так что если есть необходимость интеграции с приложением на AngularJS 2 — то вы можете взять только серверное ядро и дальше использовать его со своим интерфейсом.

                      0
                      Можно взять ядро, но тогда придется UI заново писать на Angular2. Вряд ли на это будет время при коммерческой разработке.
        0
        Основной кейс использования админки для работы с данными/ CRM?
        Пока не совсем могу придумать, где можно было использовать данный пакет…
          0

          Изначально scaffolder я начинал разрабатывать под личные потребности. В моем случае — это панель управления для небольших проектов, у которых структура базы данных достаточно простая.
          Также, я сейчас использую наработки из этого проекта в новой системе, в качестве инструмента для быстрого построения редакторов словарей. Таким образом я экономлю время, реализую вручную только формы редактирования со сложной логикой.

        Only users with full accounts can post comments. Log in, please.