T4MvcJs — строготипизированный яваскрипт-хелпер для URL

Не так давно я уже писал о решении проблемы «магических строк» в яваскрипте, примером таких строк могут служить url экшенов («/Home/Index?name=John&lastname=Doe»)

В разор-вьюшках проблему написания урлов «напрямую» можно решить с помощью T4Mvc: @Url.Action(MVC.Actions.Home.Index(«John», «Doe)). Проблема в том, что этот код — серверный, и написать что-то подобное в script.js — не получится.
В предыдущем посте я уже предлагал решение проблемы, однако(об этом я также писал) в нём была существенная недоработка. Новая версия T4MvcJs эти недоработки устраняет, и в результате мы, как и прежде, спокойно сможем писать в яваскрипт файлах что-то вроде: MvcActions.Home.Index(«John», «Doe»), и это будет полностью клиентский код.
Continue reading

Unobtrusive validation и загрузка форм через аякс (full ajax website)

При использовании «ненавязчивой» (unobtrusive) валидации форм в MVC проекте можно заметить, что если валидируемая форма была подгружена асинхронно, то валидация не сработает.

Поэтому после обновления частей страницы, содержащих формы, надо не забывать выполнить что-нибудь подобное:

$.validator.unobtrusive.parse($("#loadedContent"));

(где #loadedContent — это айдишник подгруженной области).
В простейшем случае можно даже добавить этот код в обработчик события ajaxSuccess, чтобы уж точно не забыть :)

$.ajaxSuccess(function(e) { $.validator.unobtrusive.parse(document); });

P.S. Заметить факт неработоспособности клиентской валидации может с легкостью помешать принцип graceful degradation — по-умолчанию валидация отработает нормально, но это будет серверная валидация :) При тестировании на localhost это и правда можно не заметить.

Традиционный пример проекта с этой небольшой функцией.

Повторное использование шаблонов DisplayTemplates и EditorTemplates

При работе с шаблонами отображения и редактирования достаточно быстро возникает необходимость повторного использования однажды написанных шаблонов.

Однако, по аналогии с portable areas, при попытке выноса шаблонов в отдельную сборку возникают проблемы, связанные с тем, что MVC ищет данные шаблоны в строго отведенных местах (папка ~/Views/Shared/DisplayTemplates или ~/Views/ControllerName/EditorTemplates).

Решает эту проблему очередной open-source продукт от Дэвида Эббо — Razor Generator.

Continue reading

Шаблоны отображения и редактирования форм в ASP.Net MVC (DisplayTemplates/EditorTemplates)

Шаблоны отображения и редактирования — очень мощная и полезная фича ASP.Net MVC, которую я активно использую и рекомендую всем без исключения.

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

Предположим, что в контроллере у вас есть типичная модель регистрации:

public class RegistrationModel {
    public string Login { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime Birthdate { get; set; }
    ...
}

Continue reading

Строготипизированные URL в Javascript c T4MVC

Если кто не знает, то T4MVC — это замечательная штука, которая позволяет строготипизировать в MVC3 то, что еще недостроготипизировано из коробки :)
В частности, с его помощью очень удобно генерировать ссылки на MVC-экшены в хтмл:

// в контроллере:
public ActionResult Index(int a, string b) {} 

// во вьюшке (Razor)
<a href="@Url.Action(MVC.Home.Index(10, 'some_string'))">link</a>  

//в браузере на клиенте
<a href="/Home/Index?a=10&b=some_string">link</a>

Проблемы возникают, когда параметры экшена — динамические, и их значения можно определить только в рантайме (например, параметром является какой-нибудь javascript-атрибут).
Continue reading

Русификация ASP.Net MVC3-приложений

Мой первый «коммерческий» проект на ASP.Net MVC — небольшой сервис, ориентированный на русскоговорящую аудиторию. В этой заметке я хотел бы собрать проблемы, с которыми я столкнулся в процессе «русификации» MVC3 — то есть адаптации к российской локали и русификация интерфейса и сообщений об ошибках.

Проблемы, описываемые в этом посте:

  • Указание культуры, использующейся по-умолчанию в байндингах
  • Создание кастомного байндера
  • Русификация сообщений от DataAnnotations-атрибутов
  • Русификация сообщений от дефолтного байндера
  • Проблемы интеграции локализации и Ninject

Continue reading

IoC-контейнер для ASP.Net MVC — Ninject

Уверен, что очень скоро сам забуду, почему же выбрал Ninject, так что оставлю здесь пару причин. До недавнего времени использовал Unity, но пришло время что-то менять :)

Ninject vs Unity — если «made by Microsoft» для многих является аргументом «за», то для меня, подсознательно, совсем наоборот :) По факту — Unity слабо развивается, и интеграции в MVC «из коробки» в нём банально нет. Ключевым аргументом к отказу от Unity стало отсутствие PerRequestLifetimeManager (синглтон в рамках одного запроса, очень полезен для Session/ObjectContext).

Ninject vs Castle Windsor — windsor как-то совсем не обрадовал. Опять-таки нет встроенной интеграции в MVC, нет инъекции в проперти (а в атрибуты иначе никак), и нет резолвинга классов, без их предварительной регистрации. Собственно, до «тестового приложения» здесь даже и не дошло. Совсем плохо.

StructureMap и AutoFac не рассматривались, уж больно понравилась ninject-овская интеграция :) Встает из nuget, настройки не требует вовсе (в контроллеры и атрибуты всё замечательно инъектится), очевидное место вставки регистраций, приятный синтаксис и множество тонких настроек. Да, выбор очевиден :)

Да, по скорости Ninject уступает и кастлу, и юнити, но производительность здесь не настолько критична — даже если отличие «в разы» — то все равно разница при создании десятка объектов — микросекунды. Преждевременно оптимизировать такие тонкие моменты не будем :)

Простой способ обезопаситься от CSRF в ASP.Net MVC

Наверное, все, кто занимается веб-разработкой слышали о CSRF-уязвимостях (читается sea-surf). Если быть кратким, то если у вас на сайте есть ссылки вроде http://mysite.ru/Articles/Delete/24, по которой удаляется статья с 24-ым айдишником (естественно, с проверкой прав доступа), то если авторизовавшийся на вашем сайте админ зайдет на какой-нибудь зловредный сайт, в котором подсонут яваскрипт вроде

window.location.href = "http://mysite.ru/Articles/Delete/24"

то статья с вашего сайта успешно удалится. Конечно, использовать такие уязвимости достаточно сложно, и наврядли атаку подобного типа проведут на сайт с посещаемостью в 1-2 тысячи человек. Но если вы планируете раскрутиться до уровня твиттера… :)
Впрочем, оставлять лазейки в безопасности не хочется, даже если сайт пишется для «внутренних целей», что уж говорить про продакшен.

Тем более, что MVC3 позволяет с лёгкостью таких атак избежать.
Continue reading

Portable Areas и T4MVC

В комментариях к кросспосту предыдущей статьи на хабрахабре появились вопросы о применимости T4MVC к модулям с «выделенными областями».
Это послужило для меня хорошим поводом попробовать T4MVC и осознать всю его мощь. По ходу ознакомления T4MVC был слегка модифицирован для поддержки «выделенных областей» (portable areas) и данные изменения были успешно включены в проект на codeplex автором T4MVC Дэвидом Эббо.

Ниже — детали интеграции T4MVC и Portable Areas.
Continue reading

Portable Areas как вариант модульности в MVC

Один из первых вопросов, которым я задался после знакомства с азами технологии MVC3, это способ выделения и повторного использования функционала в нескольких веб-проектах.
В WPF или WinForms все просто и понятно — обособленный функционал изолируется в модуль, модуль компилируется в библиотеку, библиотека — подключается к проекту и повторно используется. Нужно лишь грамотно изолировать модули, и всё будет хорошо.

В MVC всё не так просто, если «обособленный функционал» — это набор контроллеров и вьюшек, реализующих, допустим, гостевую книгу, то просто так вынести их в отдельный модуль нельзя — MVC просто не найдет ваши контроллеры в соседних библиотеках.

Однако решение, конечно, есть, и его нам предлагает небезызвестная библиотека MvcContrib — open-source проект, неаффилированный Майкрософтом.
Continue reading