Один из первых вопросов, которым я задался после знакомства с азами технологии MVC3, это способ выделения и повторного использования функционала в нескольких веб-проектах.
В WPF или WinForms все просто и понятно — обособленный функционал изолируется в модуль, модуль компилируется в библиотеку, библиотека — подключается к проекту и повторно используется. Нужно лишь грамотно изолировать модули и всё будет хорошо.
В MVC, если «обособленный функционал» — это набор контроллеров и вьюшек, реализующих, допустим, гостевую книгу, их можно обособить в виде «области» — area. Однако просто так вынести эту область в отдельный модуль нельзя — MVC просто не найдет ваши контроллеры/вьюшки в соседних библиотеках.
Однако решение, конечно, есть, и его нам предлагает небезызвестная библиотека MvcContrib — open-source проект, неаффилированный Майкрософтом.
Допустим, что у вас уже есть на сайте гостевая книга и есть желание повторно использовать её в другом проекте. Что надо сделать?
Создание модуля на этом завершено :) Как его использовать? Очень просто. В основной проект добавляем референсы на модуль и MvcContrib (ну и Microsoft.Web.Mvc пригодится :)). Создаем папку Areas и копируем Web.config из папки Views в папку Areas.

Всё. Запускаем проект и заходим на localhost/Guestbook/Guestbook (первый guestbook — имя области, второй — имя контроллера).
На экшены из модуля можно также ставить ссылки и подключать их с использованием RenderAction — всё, как с обычными контроллерами.
Однако, чтобы строготипизированные ссылки работали, контроллеры внутри выделенной области надо обозначить атрибутом ActionLinkArea(«AreaName»):
P.S. Ну и последний бонус для тех, кто хочет заставить это работать на linux под Mono.
На данный момент придется создать две папки Areas в структуре рабочего проекта на сервере — с большой буквы «A» и с маленькой. Необходимость в «маленькой» — баг со стороны библиотеки MvcContrib (она осуществляет предварительные проверки). Патч на этот баг отправлен разработчикам (патч в один символ :)).
P.P.S. Удивлен, что тема абсолютно не освещалась на хабре, да и в рунете особенно ничего нет.
P.P.P.S. В комментариях затронули тему применимости T4MVC для «выделенных областей». После небольшого патча T4MVC замечательно работает. Детали интеграции можно прочитать по ссылке
В WPF или WinForms все просто и понятно — обособленный функционал изолируется в модуль, модуль компилируется в библиотеку, библиотека — подключается к проекту и повторно используется. Нужно лишь грамотно изолировать модули и всё будет хорошо.
В MVC, если «обособленный функционал» — это набор контроллеров и вьюшек, реализующих, допустим, гостевую книгу, их можно обособить в виде «области» — area. Однако просто так вынести эту область в отдельный модуль нельзя — MVC просто не найдет ваши контроллеры/вьюшки в соседних библиотеках.
Однако решение, конечно, есть, и его нам предлагает небезызвестная библиотека MvcContrib — open-source проект, неаффилированный Майкрософтом.
Допустим, что у вас уже есть на сайте гостевая книга и есть желание повторно использовать её в другом проекте. Что надо сделать?
- Создать проект типа ClassLibrary и добавить в него референсы на System.Web.Mvc.dll, System.Web.Razor.dll (если вьюшки используют Razor), MvcContrib.dll и Microsoft.Web.Mvc.dll (последняя — для поддержки строгой типизации, можно пропустить).
- Создать структуру проекта, очень похожую на обычный MVC-шаблон. Единственное отличие, что папки Views, Controllers, etc. должны расположиться в корневой папке с именем нашей выделяемой области (portable area). В примере это — Guestbook. В данную структуру скопировать вьюшки и контроллеры, которые хочется обособить.
Всем вьюшки в области необходимо выставить метод компиляции — embedded resource (как подсказывают в комментариях можно также копировать вьюшки в папку Areas основного проекта — MVC их там найдет)!
- Создать регистрационный класс, который и позволит связать основное MVC-приложение и выделенную область. Класс этот должен наследоваться от PortableAreaRegistration. В простейшем случае он может выглядеть так:
public class GuestbookRegistration : PortableAreaRegistration { public override string AreaName { get { return "Guestbook"; } } }
Единственный необходимый параметр — это поле AreaName с названием области.
Однако, здесь же можно и изменить маршруты для выделенной области:
public class GuestbookRegistration : PortableAreaRegistration { public override string AreaName { get { return "Guestbook"; } } public override void RegisterArea(AreaRegistrationContext context, IApplicationBus bus) { base.RegisterArea(context, bus); context.MapRoute( "Guestbook_Default", "GuestbookPro/{action}/{id}", new { controller = "Guestbook", action = "Index", id = UrlParameter.Optional }); } }
Дефолтный маршрут выглядит, как нетрудно догадаться, так: AreaName + "/{controller}/{action}/{id}". То есть полный путь до индексового экшена по умолчанию будет выглядеть как http://localhost/Guestbook/Guestbook/Index.
Создание модуля на этом завершено :) Как его использовать? Очень просто. В основной проект добавляем референсы на модуль и MvcContrib (ну и Microsoft.Web.Mvc пригодится :)). Создаем папку Areas и копируем Web.config из папки Views в папку Areas.

Всё. Запускаем проект и заходим на localhost/Guestbook/Guestbook (первый guestbook — имя области, второй — имя контроллера).
На экшены из модуля можно также ставить ссылки и подключать их с использованием RenderAction — всё, как с обычными контроллерами.
@(Html.ActionLink<GuestbookController>(x => x.Index(), "строготипизированная ссылка на гостевую"));
@Html.ActionLink("нестроготипизированная ссылка на гостевую", "Index", "Guestbook", new { area = "Guestbook" }, null);
@{ Html.RenderAction<GuestbookController>(x => x.Index()); }
@{ Html.RenderAction("Index", "Guestbook", new { area = "Guestbook" }); }
Однако, чтобы строготипизированные ссылки работали, контроллеры внутри выделенной области надо обозначить атрибутом ActionLinkArea(«AreaName»):
[ActionLinkArea("Guestbook")]
public class GuestbookController : Controller
{
}
P.S. Ну и последний бонус для тех, кто хочет заставить это работать на linux под Mono.
На данный момент придется создать две папки Areas в структуре рабочего проекта на сервере — с большой буквы «A» и с маленькой. Необходимость в «маленькой» — баг со стороны библиотеки MvcContrib (она осуществляет предварительные проверки). Патч на этот баг отправлен разработчикам (патч в один символ :)).
P.P.S. Удивлен, что тема абсолютно не освещалась на хабре, да и в рунете особенно ничего нет.
P.P.P.S. В комментариях затронули тему применимости T4MVC для «выделенных областей». После небольшого патча T4MVC замечательно работает. Детали интеграции можно прочитать по ссылке