ASP.NET Core RC2: вбудована підтримка модульності (application parts)

Будучи історично зануреним в питання розробки модульних програми на ASP.NET перше що я зробив, коли вийшов ASP.NET Core RC2 – постарався перекласти на нього свій модульний фреймворк ExtCore. І ось тут виявилося, що в новій версії все змінилося і старі підходи з RC1 більше не працюють, зате з'явилися нові цікаві можливості, про які я і хочу розповісти.

Якщо коротко, то розробка модульних програм в RC2 дуже спрощена. Завдяки новій можливості «частини програми» (application parts), ви легко можете розділити свій великий проект на декілька більш дрібних і потім вільно компонувати їх. Особливо це зручно при роботі з областями (areas), які і так ізолюють набір контролерів, подань та інших ресурсів — кожну область тепер можна виділити в окремий проект. Наскільки я зрозумів (зокрема, aspnet/Mvc#4089), реалізація орієнтована саме на поділ великого проекту на маленькі і тільки в частині MVC. Решта все-таки доведеться писати самому.


Реалізація
Для прикладу, створимо невеликий додаток і подивимося, як все працює (передбачається, що ви вже зайшли сюди і встановили все, що потрібно). Отже, створюємо проект:



На наступному кроці вибираємо «Веб-додаток», щоб Visual Studio створила для нас готове до тестування додаток:



От і все. Тепер запустимо наше новий додаток:



Я не буду зупинятися на структурі проекту і на відмінності структури від того, до чого ми звикли в RC1. При бажанні, можна подивитися ось це.

Тепер додамо ще один проект в наше рішення, на цей раз бібліотеку класів:



Т. до. ми хочемо подивитися на роботу контролера і подання з нашої збірки, додамо в файл project.json посилання на MVC. Також нам необхідно, щоб подання в цьому проекті були додані в збірку у вигляді ресурсів. Це робиться за допомогою відповідної настройки в розділі buildOptions файлу project.json. В результаті отримаємо такий файл:

{
"buildOptions": { "embed": [ "Views/**" ] },
"dependencies": {
"Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
"NETStandard.Library": "1.5.0-rc2-24027"
},
"frameworks": {
"netstandard1.5": {
"imports": "dnxcore50"
}
},
"version": "1.0.0-*"
}


Тепер створимо в нашому проекті новий контролер з єдиним методом (для однаковості файл з класом контролера бажано помістити в папку Controllers, хоча це і необов'язково):

public class ModuleAController : Controller
{
public ActionResult Index()
{
return this.View();
}
}


Тепер в папці \Views\ModuleA створимо подання Index.cshtml з таким вмістом, який вам подобається.

Проект готовий. Зберемо його. У папці з проектом з'явиться папка bin (як в минулих версіях ASP.NET), а в ній — наша збірка. Залишилося тільки розповісти про неї основного додатка.

Відкриємо клас Startup нашого проекту програми та перейдемо до методу ConfigureServices. Першим ділом завантажимо нашу збірку з контролером і поданням:

Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"абсолютний шлях до збірки");


Далі, додамо завантажену збірку в якості частини програми в MVC:

services.AddMvc().AddApplicationPart(assembly);


Практично всі. Якщо зараз запустити додаток і перейти за адресою /modulea, ми отримаємо виняток: InvalidOperationException: The view 'Index' was not found. Щоб пояснити MVC, що шукати подання необхідно і всередині нашої збірки, додамо відповідний провайдер файлів у налаштуваннях Razor. Модифікуємо попередню рядок коду, щоб вийшло ось так:

services.AddMvc().AddApplicationPart(assembly).AddRazorOptions(
o =>
{
o.FileProviders.Add(new EmbeddedFileProvider(assembly, assembly.GetName().Name));
}
);


Наш додаток, що складається з двох частин, готово. Запустимо його, перейдемо за адресою /modulea:



Дуже здорово. Ще в RC1 для цього знадобилося б більше коду. Але цього достатньо тільки до тих пір, поки ви не захочете використовувати строго типізовані подання. Якщо додати клас моделі виду в наш проект і встановити його в якості моделі для нашого уявлення, під час виконання ми отримаємо виняток: The type or namespace name 'ModuleA' does not exist in the namespace 'AspNetCoreApplicationParts'. Пов'язано це з тим, що наша складання не входить в набір збірок, в якому Razor шукає типи при компіляції уявлень. На щастя, є досить простий спосіб це виправити. Крім того, в найближчому майбутньому в цьому кроці не буде необхідності, т. к. складання, додані як частини програми, будуть брати участь в Razor-компіляції автоматично.

Модифікуємо виклик функції AddRazorOptions, яку ми використовували на попередньому кроці, таким чином:

.AddRazorOptions(
o =>
{
o.FileProviders.Add(new EmbeddedFileProvider(assembly, assembly.GetName().Name));

Action<RoslynCompilationContext> previous = o.CompilationCallback;

o.CompilationCallback = c =>
{
if (previous != null)
{
previous©;
}

c.Compilation = c.Compilation.AddReferences(reference);
};
}
);


Залишилося оголосити змінну reference десь перед завантаженням складання:

PortableExecutableReference reference = MetadataReference.CreateFromFile(@"абсолютний шлях до збірки");


От і все. Тепер ми можемо використовувати нашу модель виду. Запустимо програму і перейдемо за адресою /modulea:



До речі, ще в RC1 можна було використовувати попередню компіляцію уявлень і не мати проблем з роздільною здатністю типів моделей видів під час виконання. На жаль, в RC2 попередня компіляція не підтримується (наскільки я зрозумів, з-за складності реалізації), але у майбутньому буде повернута.

Результат
Мабуть, application parts — саме те, чого давно не вистачало ASP.NET. Я витратив багато часу, щоб домогтися аналогічного результату в попередніх версіях (ще до ASP.NET Core). Сподіваюся, наведеного прикладу цілком достатньо, щоб почати використовувати цю можливість. І спасибі хлопцям з нашого чату Gitter, разом з якими ми розбиралися з RC2.

Весь проект цілком (у трохи спрощеному вигляді) доступний на GitHub.
Джерело: Хабрахабр

0 коментарів

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