Comments 30
/feature/models/
/feature/controllers/
/feature/views/
И models в mvc проекте все же нужны — отдавать клиенту dto, а не объекты бизнес логики, будет хорошим решением.
В MVC уже есть (были?) так называемые Areas, которые и служат для решения описанных в статье проблем.
Области (Areas) обладали еще и своей конфигурацией. Создавать по области на фичу — замаяться можно.
Тут же приведено решение, когда конфигурация для всего проекта общая, только файлы перегруппированы.
— Переименована папка Views в Features
— Для каждого контроллера все что с ним связано перенесено в его папку в папке Views
В старом ASP.NET MVC это делалось вот так:
<Target Name="GetModuleContent" DependsOnTargets="PipelineTransformPhase" Outputs="@(_Content)">
<PropertyGroup>
<ModuleName Condition="'$(ModuleName)'==''">$(AssemblyName)</ModuleName>
</PropertyGroup>
<ItemGroup>
<_Content Remove="@(_Content)" />
<_Content Include="@(FilesForPackagingFromProject)" Condition="'%(FilesForPackagingFromProject.FromTarget)' == 'CollectFilesFromContent'">
<DestinationRelativePath>Areas\$(ModuleName)\%(FilesForPackagingFromProject.DestinationRelativePath)</DestinationRelativePath>
</_Content>
<_Content Include="@(FilesForPackagingFromProject)" Condition="'%(FilesForPackagingFromProject.FromTarget)' != 'CollectFilesFromContent'">
<DestinationRelativePath>%(FilesForPackagingFromProject.DestinationRelativePath)</DestinationRelativePath>
</_Content>
</ItemGroup>
</Target>
<Target Name="CopyChildContent" BeforeTargets="CopyAllFilesToSingleFolderForMsdeploy">
<ItemGroup>
<_ChildContent Remove="@(_ChildContent)" />
</ItemGroup>
<MSBuild Projects="@(ProjectReference)" Targets="GetModuleContent" RebaseOutputs="true" Condition="'%(ProjectReference.CopyContent)'=='true'">
<Output TaskParameter="TargetOutputs" ItemName="_ChildContent" />
</MSBuild>
<ItemGroup>
<FilesForPackagingFromProject Include="@(_ChildContent)" Exclude="@(FilesForPackagingFromProject)" />
</ItemGroup>
</Target>
Ну и для отладки в IIS надо еще виртуальный путь настроить.
ResourceProvider не нужен, достаточно ControllerFactory.
Нет. За это отвечает интерфейс IViewEngine
. Надо унаследоваться от RazorViewEngine
и перегрузить методы FindPartialView
и FindView
.
А замена VirtualPathProvider для этих целей — из пушки по воробьям. Костылем.
Э… что-то я не понял как вы собрались перекомпилировать представление из VirtualPathProvider.
Во-первых, VirtualPathProvider не управляет компиляцией, он только сообщает информацию о файлах!
Во-вторых, нет никакого смысла делать то, что уже реализовано в BuildManager.
Просто есть такой класс как CacheDependency и его можно использовать, чтобы уведомить об изменении представления (например, я редактирую представления «на лету» на продакшене или во время отладки).
А еще есть сильный минус в RazorViewEngine на первый взгляд. Сейчас на скорую руку попробовал использовать и сразу натолкнулся на проблему. На этапе разработки сайт представляет собой набор библиотек плюс основное приложение. БОльшая часть представлений во время компиляции копируется в конечную папку в bin в основное приложение. Но мне-то надо редактировать исходный вариант представления в рантайме. То есть мне надо редактировать не файл Projects/SiteMain/bin/Debug/Views/login.cshtml, а файл Projects/SiteAuthLibrary/Views/login.cshtml. А при попытке выдать путь выше каталога приложения я получаю ошибку, что нельзя указать такой путь.
Конечно, может быть, есть варианты обхода такого поведения, но на данный момент это основное, что останавливает)
Я все еще не понимаю зачем вам иметь доступ к CacheDependency. ASP.NET сама создает этот класс в дефолтном провайдере — и сама же утилизирует его в билд-менеджере… Перекомпиляция измененных представлений вообще-то работает "из коробки" (пока вы не заменили VirtualPathProvider)!
Что же для путей к представлениям, хранящимся в других библиотеках — тут я согласен. VirtualPathProvider — один из возможных вариантов их подключения. Но я бы советовал вам подключить вручную виртуальный каталог в IIS — это позволит находиться в библиотеках еще и статике. Кроме того, это уберет из проекта отладочный код, который не нужен в релизе.
Ну и файлы из bin я бы посоветовал перенести в Areas :)
До этого работал с Laravel, там по-умолчанию группировалось все controller в одном подкаталоге, все model в другом — приходилось чаще скакать по папкам. Так как все-таки в пределах одного модуля модель / контроллер / представление больше взаимосвязанны чем разные модели и контроллеры между собою.
К примеру, на сайте надо поправить какой то раздел. Условно — в каталоге оборудования забыли вывести параметр «Поддержка HDMI». Надо слазить в контроллер, иногда в модель, потом во вьюшке поправить — и скачешь по папкам.
Поэтому, если в Студию внесут нейтивную поддержку такого представления — было бы здорово.
Э… вы все еще деплоите вручную? Кстати, откуда у вас на сервере отдельные файлы с контроллерами и моделями?
Команда msbuild /t:Package /p:PackageLocation=...
сгенерирует вам пакет для развертывания при помощи msdeploy (службы веб-развертывания). Ну и если покопаться в файле "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v*\Web\Microsoft.Web.Publishing.targets", то там можно найти еще настроек. В том числе можно собрать архив, удобный для велосипедного развертывания.
Дальше — настраивается CI...
Ах да, если надо исключить из пакета какие-то файлы, то заводите в проекте свой Target, вешаетесь на BeforeTarget="ExcludeFilesFromPackage"
и создаете Item с именем ExcludeFromPackageFiles
:
<Target Name="ExcludeTopSecretFile" BeforeTarget="ExcludeFilesFromPackage">
<ItemGroup>
<ExcludeFromPackageFiles Include="TopSecretFile.txt">
<FromTarget>ExcludeTopSecretFile</FromTarget>
</ExcludeFromPackageFiles>
</ItemGroup>
</Target>
Структура «Feature Folders» в ASP.NET Core MVC