Готуємо ASP.NET Core: створюємо свій багатоплатформовий модульний фреймворк

Ми продовжуємо нашу колонку по темі ASP.NET Core черговою публікацією від Дмитра Сікорського ( DmitrySikorsky — керівника компанії «Юбрейнианс» з України. Цього разу Дмитро розповідає про свій досвід розробки модульного міжплатформового фреймворку на базі ASP.NET Core. Попередні статті з колонки завжди можна прочитати за посиланням #aspnetcolumn — Володимир Юнев
З-за специфіки моєї завдання, останнім часом досить багато доводиться міркувати про модульної та розширюваної архітектурі веб-додатків на ASP.NET Core (а до цього — на ASP.NET попередній версії). В результаті з'явився ExtCore — невеликий багатоплатформовий фреймворк з відкритим кодом, що дозволяє буквально простим підключенням NuGet-пакету перетворити ваш веб-додаток в модульне і розширюване.



Основні можливості
ExtCore вміє виявляти і використовувати типи (а також представлення і статичний контент), визначені як в проектах (у вигляді вихідного коду або NuGet-пакетів), на які є явні посилання в залежностях, так і в проектах, які розміщені в певній папці у вигляді скомпільованих DLL-збірок.

Для зручності, опціонально, ці проекти можуть бути умовно об'єднані в розширення (тобто кожне розширення може складатися з одного або багатьох проектів). Також, кожне розширення може мати клас (в одному з проектів), що реалізує інтерфейс IExtension, а ExtCore, в свою чергу, дозволяє в будь-який момент отримати доступний набір екземплярів всіх класів, що реалізують цей інтерфейс. Ці класи можна використовувати для надання метаданих, що описують розширення, ініціалізації розширень (наприклад, реєстрації маршрутів) і т. д.

Хоча безпосередньо сам фреймворк і не містить будь-якого функціоналу, пов'язаного з роботою з даними, але все, що для цього необхідно (в т. ч. єдиний контекст сховища для всіх розширень), реалізовано в розширенні ExtCore.Data, про який нижче.

aspnetcolumngithubПорада! Ви можете спробувати все самостійно або завантаживши вихідний код з GitHub https://github.com/ExtCore/ExtCore-Sample.
Як це працює
Під час запуску програми ExtCore виявляє всі збірки (ті, на які є явні посилання, і ті, на які явних посилань немає, але які розміщені в певній папці). Відбираються і завантажуються лише збірки, які містять посилання на ExtCore.Infrastructure.

Далі, всі виявлені збірки, які відповідають критеріям відбору, поміщаються в клас-контейнер ExtensionManager, звідки вони можуть бути отримані в будь-який момент звідки завгодно (тобто як основного проекту програми, так і з будь-якого іншого проекту). Ці збірки «реєструються» як джерела для пошуку контролерів (всі контролери із збірок, на які є явні посилання, виявляються ASP.NET автоматично, а от про решту потрібно повідомити додатково «вручну»), уявлень (і у вигляді ресурсів, і попередньо скомпільованих) і статичного контента.

Після цього проводиться виконання ряду методів IExtension серед доступних екземплярів реалізацій цього інтерфейсу. Так розширення отримують можливість виконати свій код під час виконання методів ConfigureServices, Configure і т. д.

Рекомендована структура розширення
Для спрощення розуміння і збереження одноманітності, зручно дотримуватися наступної структури при розробці власних розширень (де X — назва вашого розширення):

  • YourApplication.X;
  • YourApplication.X.Frontend;
  • YourApplication.X.Backend;
  • YourApplication.X.Data.Models;
  • YourApplication.X.Data.Abstractions;
  • YourApplication.X.Data.SpecificStorageA;
  • YourApplication.X.Data.SpecificStorageB;
  • YourApplication.X.Data.SpecificStorageC;
  • і так далі.
YourApplication.X

Основний проект розширення. Містить клас, який реалізує інтерфейс IExtension, а також загальні класи, використовувані в інших проектах. Якщо розширення не містить різних областей (наприклад, фронтенд і бекенд), то стосуються інтерфейсу речі (контролери, моделі видів, подання тощо) також можна розмістити в цьому проекті.

YourApplication.X.Frontend іYourApplication.X.Backend

Проекти названі так лише для прикладу. Мені здається зручним розділяти таким чином різні частини користувальницького інтерфейсу (особливо при командній роботі). Також, якщо веб-додаток складається з великої кількості розширень, можна винести загальні елементи фронтенда і бек-ендом в базові проекти і потім посилатися на них у всіх інших. Таким чином, наприклад, розширення можуть мати однаковий зовнішній вигляд або набір базових елементів управління з можливістю простий його заміни шляхом копіювання того чи іншого DLL-файлу.

ExtCore підтримує два варіанти для роботи з уявленнями (одночасно): подання у вигляді ресурсів і попередньо скомпільовані подання. Якщо коротко, я рекомендую використовувати другий варіант. Більш докладно про методи роботи з уявленнями, застосованими в ExtCore, можна почитати в статті «Готуємо ASP.NET Core: поговоримо про нестандартні підходи при роботі з уявленнями» (https://habrahabr.ru/company/microsoft/blog/276061/).

Робота зі статичним контентом також не викликає утруднень. У статті «Готуємо ASP.NET Core: як представити статичний контент у вигляді ресурсів» (https://habrahabr.ru/company/microsoft/blog/277235/) докладно описаний використовуваний в ExtCore метод. Якщо резюмувати цю статтю, то необхідний статичний контент поміщається в збірки у вигляді ресурсів і потім ці збірки «реєструються» як постачальники файлів (file providers), що робить можливим використання ресурсів практично як звичайних фізичних файлів (у т. ч. з прямим доступом по HTTP).

Цікаво, що областю видимості як уявлень, так і статичного контенту є додаток. Це означає, що одні розширення можуть використовувати вміст інших розширень і навпаки. Більш того, розширення можуть використовувати подання та статичний контент з основного веб-додатки. Таким чином можна, наприклад, описати логіку в проектах розширення, але дати можливість користувачеві визначити те, як все буде виглядати, прямо в основному додатку.

YourApplication.X.Data.*

Проекти, що описують роботу з даними. Більш докладно про це-нижче.

Робота з даними

ExtCore додатково має опціональне розширення ExtCore.Data, що реалізує весь необхідний базовий функціонал для роботи з даними. Центральним елементом розширення є інтерфейс IStorage (одиниця роботи). Цей інтерфейс описує всього 2 методу: GetRepository і Save. Реалізація GetRepository виявляє і повертає доступний примірник репозиторію, що реалізує запитаний інтерфейс (а також, IRepository) і стежить за тим, щоб всі репозиторії мали єдиний контекст сховища (інтерфейс IStorageContext).

Якщо потрібна якась реєстрація типів сутностей з різних розширень (як, наприклад, у випадку з EntityFramework), це може бути легко досягнуто за допомогою чогось на зразок інтерфейсу IModelRegistrar, який застосовується в ExtCore.Data.EntityFramework.Sqlite і ExtCore.Data.EntityFramework.SqlServer. Тестовий проект (посилання в кінці статті) ілюструє цей підхід.

Структура розширення наступна:

  • ExtCore.Data;
  • ExtCore.Data.Models.Abstractions;
  • ExtCore.Data.Abstractions;
  • ExtCore.Data.EntityFramework.Sqlite;
  • ExtCore.Data.EntityFramework.SqlServer.
ExtCore.Data

Проект містить клас, який реалізує інтерфейс IExtension. Цей клас при запуску програми виконує код, який виявляє доступну реалізацію інтерфейсу IStorage (див. нижче) і реєструє її у вбудованому в ASP.NET Core DI, щоб будь-контролер потім зміг отримати її примірник при необхідності. Зручно, що можна змінювати тип підтримуваної сховища шляхом простої зміни посилання в залежностях або копіювання DLL-файлу.

ExtCore.Data.Models.Abstractions

Проект описує інтерфейс IEntity, який повинні реалізувати всі сутності у всіх розширень.

ExtCore.Data.Abstractions

Проект описує ключові інтерфейси IStorageContext, IStorage і IRepository, про які я розповів вище. У власних розширень в проекти з іменами на зразок YourApplication.X.Data.Abstractions я розміщую інтерфейси репозиторіїв, щоб потім працювати через них без прив'язки до реалізації конкретного сховища.

ExtCore.Data.EntityFramework.Sqlite і ExtCore.Data.EntityFramework.SqlServer

Проект містить класи, що реалізують інтерфейси з ExtCore.Data.Abstractions для конкретних сховищ (в даному випадку це Sqlite і SqlServer).

Висновки
В даний момент — це лише альфа-версія. У мене є багато планів щодо розвитку проекту (підключення і відключення розширень в будь-який момент і загальна оптимізація; також хочу попрацювати над класом ExtensionManager, додати зручну можливість отримання доступних реалізацій заданих інтерфейсів, а не тільки IExtension). Я використовую цей фреймворк у своєму проекті (CMS). Наскільки можу судити — вийшло зручно і гнучко. Буду радий почути зауваження та критику. Спасибі!

Ось посилання на джерело: https://github.com/ExtCore/ExtCore.

А ось посилання на готовий тестовий проект: https://github.com/ExtCore/ExtCore-Sample.

Авторам
Друзі, якщо вам цікаво підтримати колонку своїм власним матеріалом, то прошу написати мені на vyunev@microsoft.com для того, щоб обговорити всі деталі. Ми шукаємо авторів, які можуть цікаво розповісти про ASP.NET та інші теми.

Про автора
Сікорський Дмитро Олександрович
Компанія «Юбрейнианс» (http://ubrainians.com/)
Власник, керівник
DmitrySikorsky

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.