воскресенье, 19 февраля 2012 г.

Добавляем MVC к проекту Web Forms

Здравствуйте. Сегодня поговорим о веб разработке, а конкретно о MVC и веб формах. Часто так бывает, что хочется добавить мощь MVC к существующему проекту Web Forms, а переписывать весь код с нуля затратно, да и некоторые фишки в старом коде хотелось бы оставить. Именно о добавлении функциональности MVC к проекту Web Forms далее пойдет речь.

Итак, допустим, у нас есть проект Web Forms и мы хотим, чтобы некоторые из его разделов были сгенерированы посредством MVC. Давайте задумаемся, что из себя вообще представляет проект Visual Studio? По сути, это просто файл с настройками (файл проекта), в котором также перечислены все другие файлы, входяшие в этот проект. То есть что я хочу сказать - что только в этом файле то и написано, что вообще проект из себя представляет веб-сайт, а не, например, службу Windows. А в чем кроется функциональность MVC? Oна находится в сборках MVC, и при работе с этой технологией используются классы из этих сборок. То есть было бы логично представить, если мы возьмём эти сборки, подключим к проекту, то мы можем беспрепятственно их использовать для генерации страниц, верно?

Итак, первым делом я создаю простое Web Forms приложение.

В нём абсолютно нет ничего особенного - это стандартное приложение, которое создаcтся автоматически. Далее, добавляем нужные сборки MVC. Для этого заходим в web.config и обновляем там секцию compilation

  1.   <compilation debug="true" targetFramework="4.0">
  2.       <assemblies>
  3.           <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  4.           <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  5.           <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  6.           <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  7.           <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  8.       </assemblies>
  9.   </compilation>

Затем добавляем ссылки на все эти указанные сборки (я пользуюсь MVC 3 - если Вы пользуетесь другой версией, то версия сборок должна быть Ваша).
Далее добавляем используемые пространства имен для страниц (этого можно и не делать, но мне так удобнее). Для этого добавляем секцию pages в секцию system.web файла web.config

  1. <pages>
  2.   <namespaces>
  3.     <add namespace="System.Web.Helpers" />
  4.     <add namespace="System.Web.Mvc" />
  5.     <add namespace="System.Web.Mvc.Ajax" />
  6.     <add namespace="System.Web.Mvc.Html" />
  7.     <add namespace="System.Web.Routing" />
  8.     <add namespace="System.Web.WebPages"/>
  9.   </namespaces>
  10. </pages>

Затем обновим класс Global, который находится в файле Global.asax.cs. Если честно, то я просто создал второй проект типа MVC и просто скопировал код для этого класса. Но Вы можете тут всё настроить по собственному желанию, конечно.

  1. using System.Web.Mvc;
  2. using System.Web.Routing;
  3.  
  4. namespace WebApp
  5. {
  6.     public class Global : System.Web.HttpApplication
  7.     {
  8.  
  9.         public static void RegisterGlobalFilters(GlobalFilterCollection filters)
  10.         {
  11.             filters.Add(new HandleErrorAttribute());
  12.         }
  13.  
  14.         public static void RegisterRoutes(RouteCollection routes)
  15.         {
  16.             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  17.  
  18.             routes.MapRoute(
  19.                 "Default", // Route name
  20.                 "{controller}/{action}/{id}", // URL with parameters
  21.                 new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
  22.             );
  23.         }
  24.  
  25.         protected void Application_Start()
  26.         {
  27.             AreaRegistration.RegisterAllAreas();
  28.  
  29.             RegisterGlobalFilters(GlobalFilters.Filters);
  30.             RegisterRoutes(RouteTable.Routes);
  31.         }
  32.     }
  33. }

Теперь создадим нужные нам папки Controllers, Models и Views. Работа почти закончена. Но только вот студия пока не понимает, что наш проект уже не просто Web Forms, а уже использует MVC - нет таких менюшек как Add Controller, Add View и тд. Чтобы это исправить, заглянем в сам файл проекта (для этого сгодится любой текстовый редактор). Что мы там увидим? В моём случае, файл WebApp.csproj хранится в формате XML и нам оттуда нужна только секция ProjectTypeGuids. Именно она указывает студии, какой вид проекта мы в данный момент используем (идентификаторы различных типов проектов можно поглядеть тут или тут). Приводим его к следующему виду :

  1. <ProjectTypeGuids>{E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

После этого перегружаем проект в студии. После этого можно добавить первый контроллер в проекте. Добавим контроллер HomeController и представление для него Index.aspx, где просто выведем строку Hello from ASP.NET MVC!


Но это ещё не всё. Благодаря подобным чудесным статьям можно делать даже так:


На этом всё. Всем спасибо.

UPD. В комментариях попросили добавить поддержку Razor. Нет ничего проще! Достаточно в папку Views проекта добавить файл web.config со следующим содержимым:

  1. <?xml version="1.0"?>
  2. <configuration>
  3.     <configSections>
  4.         <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
  5.             <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
  6.             <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
  7.         </sectionGroup>
  8.     </configSections>
  9.     <system.web.webPages.razor>
  10.         <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  11.         <pages pageBaseType="System.Web.Mvc.WebViewPage">
  12.             <namespaces>
  13.                 <add namespace="System.Web.Mvc" />
  14.                 <add namespace="System.Web.Mvc.Ajax" />
  15.                 <add namespace="System.Web.Mvc.Html" />
  16.                 <add namespace="System.Web.Routing" />
  17.             </namespaces>
  18.         </pages>
  19.     </system.web.webPages.razor>
  20. </configuration>

После этого можно использовать представления Razor.

8 комментариев:

  1. Хорошая базовая статья. Еще было бы неплохо дописать про то, как добавить поддержку Razor.

    ОтветитьУдалить
  2. Я поступаю наоборот - создаю MVC проект, и добавляю web-form стандартным способом

    ОтветитьУдалить
    Ответы
    1. Это то понятно. Я же имел ввиду, когда Web Forms проект уже есть и содержит какой то полезный код. Тогда добавить К нему функционал MVC проще, чем переносить весь код в другой проект.

      Удалить
  3. Будет ли работать Razor на Web Forms?
    Спрашиваю не потому что лень проверить, а потому что ошибка при самостоятельной проверке убедит меня в неверном ответе.

    ОтветитьУдалить
    Ответы
    1. Не совсем понял вопрос. Если вы имеете ввиду совместное использование MVC представлений, написанных с использованием Razor, с веб формами - то я это и показал на последнем скриншоте. Если же делать веб форму, чтобы файл представления был написан на Razor - я не думаю, что это целесообразно. Хотя, если подумать, как работает веб:
      1. Клиент посылает запрос на сервер
      2. Сервер генерирует ответ и отправляет клиенту
      3. Клиент работает с ответом и может послать второй запрос на сервер (к примеру, постбек)
      Таким образом, если с помощью Razor можно будет сгенерировать разметку, аналогичную той, что генерирует стандарнтый движок (пункт 2), то можно будет организовать и постбек. Только не для этого Razor предназначен. Почитайте Скотта Гатри (русский английский) - он же пояснял, что Razor в первую очередь предназначен для рендеринга MVC представлений.

      Удалить
  4. Спасибо Артем. Это как раз то, что я искал

    ОтветитьУдалить
  5. Артем - Спасибо!
    Изложено просто и понятно. Сейчас буду делать в существующем проекте (Web Forms) новый функционал с использованием MVC. Ваша статья очень по делу.

    ОтветитьУдалить