Дмитpий Hecтepук

Блог о программировании — C#, F#, C++, архитектура, и многое другое

Мои первые шаги при создании Asp.Net MVC приложения

16 комментариев

Каждый раз когда я начинаю новый проект на Asp.Net MVC, всегда выполняю кучу ритуальных действий, которые уже приелись. Вот небольшой список того, что я делаю слишком часто (и пора бы уже вынести это в отдельный темплейт).

  • Определение базового класса контроллера. Это полезно для миллиона вещей, например для предоставления всем контроллерам быстрого доступа к сервисам, которые они используют. Единственный недочет так это то что у нас теперь есть AsyncController, так что получаются либо два разных базовых класса либо множественное наследование.

  • Добавление в базовый класс обработчика отсутствующих путей, а также добавление страницы Http404.aspx для показа простенького сообщения об ошибке. Сам обработчик несуществующих путей выглядит так:

    protected override void HandleUnknownAction(string actionName)
    {
      actionName = "Http404";
      this.View(actionName).ExecuteResult(ControllerContext);
    }
    

  • Переписывание routing правил на свой лад – ненавижу когда при одном лишь контроллере все пути выглядят как http://site.com/Home/whatever. Зачем нам вообще Home показывать? Правильно – не надо. Для всех «одноуровневых» действий мы хоть и исползуем HomeController но Home из пути удаляем. Для «полноценных» контроллеров мы просо прописываем роутинг. Получается вот это:

    private static readonly string[] controllers = new[] {"Admin", "Query", "Account", "Cart"};
    public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      foreach (var c in controllers)
      {
        routes.MapRoute(
          c,
          c.ToLowerInvariant() + "/{action}/{id}",
          new {controller = c, action = "Index", id = string.Empty});
      }
      // no controller in route!!!
      routes.MapRoute(
          "Default",                                        
          "{action}/{id}",
          new { controller = "Home", action = "Index", id = "" }
      );
    }
    

  • Добавление в мастер-страницу placeholder’а для вставки в <head> и удаление placeholder’а для вставки в <title>. Идея совмещение кусков титула работает плохо. В смысле, либо вы этим не занимаетесь вообще (и у вас везде один <title>), либо вы подходите к вопросу серьезно, в результате чего у вас будет какой-то сложный компонент который строит многоуровневые заголовки вроде Умная Статья / Дмитрий Нестерук/ GotDotNet.ru.

    Что же касается вставки в <head>, делается это для того чтобы конкретная страничка могла подключать свои стили или скрипты. Обычно нужны скрипты которые используют, скажем, jQuery+AJAX но вставлять их в aspx-файл как-то некомильфо, поэтому они выносятся в отдельный скрипт, в котором, хочу заметить, первой строкой обычно идет ссылка на vsdoc для jQuery – чтобы легче работалось.

    Иногда в процессе фигурирует также вставка ‘tail’ (TailContent). Суть в том, что некоторые скрипты хочется выполнять когда вся страница загружена. Следовательно, для этого тоже полезно иметь placeholder. Правда я им в большинстве случаев все-таки пренебрегаю, и просто использую MainContent.

  • Добавление ссылок на jQuery и, почти всегда, на jQuery UI. Вы все еще используете обычные кнопки и Html.ActionLink-ы? Тогда мы идем к вам. Да, обычно для кнопок приходится прописывать стили и вставлять скрипты для «подсветки». Подробности тут.

  • Аннигиляция MembershipProvider‘а, если это только не действительно нужно (а даже если нужно, приходится все перелопачивать). Думаю этот шаг более менее очевиден.

  • Далее часто следует подвязка всех самых нужных библиотек, таких как Telerik MVC, MbUnit, Unity и так далее, в зависимости от проекта.

Конечно, всегда можно воспользоваться таким темплейтом как SharpArchitecture, но в 99% случаев это просто overkill. ■

Advertisements

Written by Dmitri

24 февраля 2010 в 1:03

Опубликовано в asp.net

комментариев 16

Subscribe to comments with RSS.

  1. Могу также добавить из своего опыта — создание базового класса для view models тоже во многих случаях упрощает жизнь.

    Дмитрий

    24 февраля 2010 at 18:55

    • Спасибо за идею, как-то пока такое в голову не приходило.

      Dmitri

      24 февраля 2010 at 20:04

  2. Вообще, хорошие замечания. За исключением некоторых деталей делаю все аналогично. Видимо, с этим так или иначе сталкиваются все, кто интенсивно юзает Asp.net MVC.

    Дмитрий

    24 февраля 2010 at 18:59

  3. Для тайтлов лучше сделать поле PageTitle у базовой ViewModel (ее тоже обязательно делаю) (не типизированные страницы это зло:)
    и в Master Page выводить его в качестве тайтла.

    А как вам контролы от Telerik ? Grid например?
    В некоторых случаях он ведет себя странно, и вместо аякс-запросов посылает полноценные и перезагрузкой страницы.

    devlanfear

    24 февраля 2010 at 19:10

    • Telerik MVC Grid с MVC1 работал идеально — с AJAXом никаких проблем не было, хотя были проблемы с тем как он выписывал имя пути для вызова — начало падать когда я приложения стал как виртуальные пути в IIS добавил. Вроде разрулил это.

      Что касается MVC2, то тут пока проблемки, о которых Telerik уже извещен. Пока что все крутится через server binding т.к. c AJAX-вызовами что-то не то.

      Dmitri

      24 февраля 2010 at 19:22

      • Проблемы с Телериком были именно с MVC 2. Значит будем ждать.
        Пока взял jqGrid в качестве грида. Доволен :)

        devlanfear

        26 февраля 2010 at 18:56

  4. маршруты бред!

    В данном случае необходимо воспользоваться constraint. Что вы будете делать, когда контроллеров у вас будет 9000? или стопицот?

    hazzik

    24 февраля 2010 at 22:33

  5. такой вариант:

    class NotHome : IRouteConstraint {
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
    var controller = values[parameterName].ToString();
    return controller.Equals("home", StringComparison.InvariantCultureIgnoreCase) == false;
    }
    }

    routes.MapRoute("Default",
    "{controller}/{action}/{id}",
    new {id = ""}, //пришлось пожертвовать default action
    new {controller = new NotHome()});

    routes.MapRoute("HomeRoutes",
    "{action}/{id}",
    new {controller = "Home", action = "Index", id = ""});

    Либо использовать перечисление контроллеров, как у вас в примере:

    class ControllersIn : IRouteConstraint {
    private readonly string[] controllers;

    public ControllersIn(params string[] controllers) {
    this.controllers = controllers;
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) {
    var controller = values[parameterName].ToString();
    return controllers.Contains(controller, StringComparer.CurrentCultureIgnoreCase);
    }
    }

    routes.MapRoute("Default",
    "{controller}/{action}/{id}",
    new {id = "", action = "Index"},
    new {controller = new ControllersIn("Account")});

    routes.MapRoute("HomeRoutes",
    "{action}/{id}",
    new {controller = "Home", action = "Index", id = ""});

    А вообще к прописыванию маршрутов нужно относиться с осторожностью. ИМХО, но опциональный параметр "id" большинство людей вводит в заблуждение.

    hazzik

    24 февраля 2010 at 23:45

    • Ваш вариант — массовое убийство невинных, IRouteConstraint это конечно здорово, но как-то нечитабельно и не очень оправданно, особенно когда контроллеров мало. Часто ли их бывает больше десятка? Конечно задачи бывают разные, но у меня много проектов где вообще один контроллер.

      Dmitri

      25 февраля 2010 at 15:31

      • Вы кроме слов overkill другие знаете?

        hazzik

        25 февраля 2010 at 16:02

  6. > Конечно, всегда можно воспользоваться таким темплейтом как SharpArchitecture, но в 99% случаев это просто overkill.

    Говоря это, Вы имели в виду и Enterprise разработку? Если да, то в чем он (overkill) выражается?

    ifa

    25 февраля 2010 at 10:15

  7. Статья хорошая. Ваши шаги можно точно можно считать за темплейт. Только в кусок кода я дописал так:
    actionName = «Http404»;
    ControllerContext.HttpContext.Response.StatusCode
    = 404; this.View(actionName).ExecuteResult(ControllerContext);

    Всё верно?

    г-н Тараканофф

    15 мая 2010 at 14:21

  8. Хотелось бы узнать про «Аннигиляция MembershipProvider» — как именно это лучше делать, спасибо

    Артем

    3 мая 2011 at 13:08

    • Насколько я помню, дефолтный шаблон в те времена когда я написал пост поставлялся с расписаным «по всем канонам» MembershipProvider’ом. Реально там нужны 2-3 метода, а если учесть как злостно реализован дефолтный подход (какая-то магическая база данных IIS), то моя рекоммендация — давить нещадно. Если нужно, то для той же MongoDB провайдеры (Membership- и вроде еще Authentication) пишутся за 5 секунд. Просто в большинстве мест ставится throw new NotImplementedException(), и все.

      Сама по себе парадигма — эпичный архитектурный фейл, кстати.

      Dmitri

      3 мая 2011 at 21:57

  9. Мне понравилось следующее решение для устранения Home. В MVC4 есть класс RouteConfig, в котором добавляются маршруты. Можно привести метод RegisterRoutes к виду:

    public static void RegisterRoutes(RouteCollection routes)
    {
    routes.IgnoreRoute(«{resource}.axd/{*pathInfo}»);

    routes.MapRoute(
    «OnlyAction»,
    «{action}»,
    new { controller = «Home», action = «Index» }
    );

    routes.MapRoute(
    name: «Default»,
    url: «{controller}/{action}/{id}»,
    defaults: new { controller = «Home», action = «Index», id = UrlParameter.Optional }
    );
    }

    Михаил

    6 декабря 2012 at 22:48


Оставить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: