Pull to refresh

Осваиваем ASP.NET MVC вместе. Введение

Reading time8 min
Views20K

Немного предыстории


Я с другом всецело интересуемся веб-разработкой и всем что с ней связано. В этом году университету дали заказ написать веб-портал для студентов, в котором можно будет получить последнюю информацию о оценках, расписание… Но об этом потом. Естесственно «Конструкторское Бюро» (так называется отдел который отвечает за разработку программного обеспечения в университете), не долго думая, решили перебросить задание на студентов. Так уж случилось, что мы попали в число этих студентов и на выбор нам предложили ASP.NET Web Forms или PHP Symfony. И дабы усложнить себе задание и выучить что-то новое, мы попросили разрешить нам сделать задание на ASP.NET MVC. Проект сейчас всецело развивается, и я думаю как закончим, мы выложим исходные коды проекта сюда. Но об этом тоже потом. И так, дабы как-нибудь систематизировать наши знания и получить советы от профессионалов, мы решили начать серию статей, которые могут помогут начать другим людям изучать этот прекрасный фреймворк. Ну что ж? Начнем!

И так, для роботы нам понадобится как минимум следующие вещи:

Мы предлогаем создать проект с нуля, это позволит лучше понять как работает и строится ASP.NET MVC проект, к тому же мне не нравится демо код, который присутствует при стандартном создании проекта.


Начнем с чистого листа


Начнем с того, что создадим проект Class Library для C#. Теперь удалим с него все лишнее: Class1.cs, AssemblyInfo.cs с директории Properties и все что есть в References. В итоге получим просто пустой проект.

Типы проектов


Все мы знаем, что Visual Studio поддерживает множество разных типов проектов, с каждым из которых студия работает по разному. К примеру, если мы попытаемся запустить созданный нами Class Library project (Ctrl-F5), то получим следующее сообщение:

A project with an Output Type of Class Library cannot be started directly.

Поскольку нашей целью является создание ASP.NET MVC проекта, то изменим тип нашего проекта соответственно. Для этого выбираем пункт Unload Project с контекстного меню проекта, откроем файл проекта на редактирование (правой кнопкой по проекту — Edit) и добавляем Guid для проектов типа Class Library:

<ProjectTypeGuids>{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

А теперь добавим Guid для Web Application:

<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>

Обратите внимание на то, что Guid для Web Application должен обязательно быть первым, иначе VS не перезагрузит проект.

После того как мы перезагрузим проект (правой кнопкой по файлу проекта — Reload Project), мы видим, что иконка проекта изменилась. Если теперь попробовать запустить проект, то студия запустит эксплорер. Кроме того, поскольку для нормальной работы Web Application нужны дополнительные настройки, то после перезагрузки проекта студия подкорректирует секцию конфигураций ProjectExtensions.

Завершающим этапом в изменении типа нашего проекта будет корректировка Output path проекта на bin \. Для этого в свойствах проекта перейдем на вкладку Build и изменим Output path.
image

Настройка маршрутизации


В ASP.NET MVC, как и в большинстве других MVC фреймворков, URL не отображают фактический путь к файлу на диске, как это реализовано в ASP.NET WebForms. В MVC урл имеет более интуитивно понятный вид [контроллер/действие], это преобразование называется routing и для того чтобы оно работало корректно — нам нужно внести некоторые изменения в проект.

Прежде всего добавим Web.config. Очистим его и добавим следующее:

<httpModules>
  <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>


Этот модуль нужен для проверки соответствий запрашиваемой URL с заданными маршрутами и если соответствие найдено, HttpHandler берет управление на себя.

Создадим наше первое приложение


Определение маршрутизации лучше всего выполнять на старте приложения (Application_Start). Для этого нам нужно добавить в проект Global Application Class(Global.asax файл). Я предпочитаю заменять файл Global.asax.cs (codebehind file) на свой Application.cs.
Получаем следующий Global.asax:

<%@ Application Inherits="Mvc.Application" %>

Определение маршрутов


После того, как мы добавили Global Application Class, Visual Studio добавила несколько ссылок (references) к проекту:
image

Добавим еще ссылку на сборку System.Web.Routing. (Эта сборка устанавливается с NET 3.5 Service Pack 1)
Далее добавляем вызов метода RegisterRoutes в Application_Start:

using System.Web;

namespace Mvc
{
  public class Application : HttpApplication
  {
    public void Application_Start()
    {
      Router.RegisterRoutes(RouteTable.Routes);
    }
  }
}


Для определение роутов я использую класс Router, который мы определим позднее. Обратите внимание на RouteTable.Routes — это коллекция типа RouteCollection, которая будет содержать все маршруты нашего приложения, а метод RegisterRoutes заполняет эту коллекцию данными. Сам маршрут(route) содержит в себе информацию о том, каким образом нужно обрабатывать запрос.

routes.MapRoute(
 "Default",            // Route name
 "{controller}/{action}/{id}",       // URL with parameters
 new { controller = "Home", action = "Index", id = "" } // Parameter defaults
 );


UrlRoutingModule сопоставляет текущий запрос с определенными нами маршрутами и обрабатывает его соответствующим образом. Если запрос соответствует одному из заданных нами маршрутов, то RouteHandler передает управление HttpHandler.

Теперь, добавим ссылку на сборку System.Web.Mvc и определим сам класс Router. Класс Router будет иметь вид:

using System.Web.Mvc;
using System.Web.Routing;

namespace Mvc
{
  public static class Router
  {
    public static void RegisterRoutes(RouteCollection routes)
    {
      Route route = new Route("{controller}/{action}", new MvcRouteHandler());
      routes.Add(route);
    }
  }
}


MvcRouteHandler создаст экземпляр MvcHandler, который обрабатывает запросы, базируясь на данных с RequestContext.
Маршрут (Route) должен содержать информацию о том, какой контроллер использовать (инстанциировать) и какой метод этого контроллера вызывать.


Добавление контроллеров


Добавим контроллер в директорию Controllers, которая обычно содержит все контроллеры:

using System.Web.Mvc;

namespace Mvc.Controllers
{
  public class HomeController : Controller
  {
    public string Index()
    {
      return "Hello World!";
    }
  }
}


В этом контроллере определен один метод Index(). Теперь, когда мы перейдем по адресу ~/home/indeх, мы увидим надпись «Hello World!».

Далее модифицируем метод RegisterRoutes следующим образом:

public static void RegisterRoutes(RouteCollection routes)
{
  Route route = new Route(
    "{controller}/{action}",
    new RouteValueDictionary(new { Controller = "Home", Action = "Index" }),
    new MvcRouteHandler());
  routes.Add("Default", route);
}


Фактически, мы сделали так, что метод Index, контроллера Home будет выполняться по умолчанию.То есть, если мы перейдем по адресу ~/ то мы увидим результат выполнения Index().

Добавление вида


Поскольку, возвращать всю страницу в виде строки, далеко не самая лучшая практика построения веб приложения, то мы добавим представление, которое будет содержать в себе дизайн страницы.

Создадим следующую иерархию папок Views/Home и добавим новый GUID, который укажет студии, что мы работаем с MVC проектом:

<ProjectTypeGuids>{603c0e0b-db56-11dc-be95-000d561079b0};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>


После перезагрузки проекта, нам станут доступны новые типы элементов, специфических для MVC
image

Представления и компоненты (control) наследуют System.Web.Mvc( вы можете убедиться в этом, посмотрев в директиву <%@ Page%>). WebFormsViewEngine использует тот же принцип компиляции, что и в WebForms. То есть, для корректной работы, нам нужно добавить ссылку на эту сборку в web.config:

<compilation debug="true">
  <assemblies>
    <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  </assemblies>


Далее добавим MVC View Page Index.aspx в директорию Views/Home и изменим тип, возвращаемый методом Index():

public ActionResult Index()
{
  return View();
}


Последнее, что нам нужно сделать — предотвратить прямое обращение к представлениям, которые лежат в папке Views. (Перейдите по адресу ~/views/home/index.aspx и вы увидите контент этой страницы.) Для предотвращения такой возможности добавим следующие строки в Web.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authorization>
      <deny users="*"/>
    </authorization>
  </system.web>
</configuration>


Импортирование пространств имен в сборку


Так же, как и WebForms, ASP.NET MVC представления компилируются в отдельном процессе aspnet_compiler. Пока мы не добавим ссылки на сборки, которые мы используем в приложении, в конфигурационный фал веб-приложения, компилятор не будет знать какие именно использовать.

<compilation debug="true">
  <assemblies>
    <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>    
    <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
    <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
  </assemblies>
</compilation>


Теперь компилятор будет адекватно реагировать на наши попытки использовать типы, определенные в одной из этих сборок. Теперь, для удобства, добавим пространства имен в Web.config, что позволит нам использовать короткие имена типов.

<pages>
  <namespaces>
    <add namespace="System.Collections.Generic"/>
    <add namespace="System.Linq"/>    
    <add namespace="System.Web.Mvc"/>
    <add namespace="System.Web.Mvc.Html"/>
  </namespaces>
</pages>


В последнюю версию C# было добавлено множество новых конструкций, и нам конечно же хотелось бы использовать их в наших представлениях. Для этого добавим еще несколько конфигураций:

<system.codedom>
  <compilers>
    <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <providerOption name="CompilerVersion" value="v3.5"/>
      <providerOption name="WarnAsError" value="false"/>
    </compiler>
  </compilers>
</system.codedom>


Обобщенные виды


В ASP.NET MVC есть возможность определять строго-типизированные представления, определив атрибут Inherits директивы Page используя обобщенный класс System.Web.Mvc.ViewPage.

Пример:

<%@ Page Inherits="System.Web.Mvc.ViewPage<Object>" %>

Чтобы компилятор мог понять такую конструкцию, нам нужно определить парсер в Web.config:

<pages pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
  //...
<pages>


Вот и все пока что.


Мы вручную создали ASP.NET MVC проект с минимальным набором элементов, чтобы лучше понять внутреннею структуру(работу) MVC.
Исходники можно скачать тут.

В следующий раз планируем написать статью о принцпах и методах, которые лучше применять для работы с ASP.NET MVC.
Так что продолжение следует.

P.S. Ах да, если у кого есть один лишний инвайт, то мой друг, с которым мы занимались переводом и оформлением данной статьи, тоже хотел бы попасть на хабр.
В качестве основы бралась данная статья.
Tags:
Hubs:
Total votes 56: ↑39 and ↓17+22
Comments20

Articles