Pull to refresh

Comments 36

Удивлен, что тема абсолютно не освещалась на хабре, да и в рунете особенно ничего нет

Ну наверное это не очень то и нужно. Ведь по сути для простых приложений, это вообще не нужно. А если что то серьезное, то лучше реализовать его в виде плагинов, где каждый плагин — это отдельный MVC проект, и для того чтоб его подключить к проекту, достаточно скопировать в определенную папку. Например можете изучить проект Orchard CMS, там как раз это и реализовано.
за референс на Orchard CMS спасибо, посмотрю.
Это нужно и для простых приложений, если у вас таких «простых» больше, чем одно и между ними есть общий функционал :)

Подключать «копированием в папку» — это хорошо, если у вас CMS, в которой есть стандарт для плагинов и есть GUI для их включения/выключения.
А если у вас не «плагин» как таковой, а часть сайта, с которой вы достаточно плотно работаете из основного приложения (запрашиваете данные/используете сервисы), то в подключении референса нет ничего неудобного. А совсем даже наоборот.
У меня то же были «простые» приложения, у которых в начале было 5-10% общего, а со временем это выросло до 50%. А когда таких приложений становится не 2, а 4-5, то вы поймете, как сложно сопровождать такой код.
Например, вы обнаружили ошибку, вам придется исправить его в одном проекте, далее открыть все оставшиеся и изменить там, и все сбилдить.
То же самое придется сделать, когда решите изменить/доработать.
Поэтому совет, если вы и дальше будете сопровождать такие проекты, лучше сразу начните реализовать через плагины. И не обязательно при этом писать свой CMS. Можно через IoC или DI(тем более в MVC3 все это заложено) реализовать так, чтоб MVC знал, где надо искать контроллеры, где надо искать View, а при желании можете и URL переопределить и тогда не далеко и до своей CMS-ки :)
Я как-то видимо неправильно выразился в топике, что ли.

Я как раз про выделение функционала в отдельные модули = отдельные .dll-ки.
Отличие от плагинов минимальное, насколько я понимаю. Найден баг — исправляем в одном месте — в .dll-ке.
Занятно. Но вот что-то мне подсказывает, что разного рода библиотеки и тулзы (вроде T4MVC), которые рассчитаны на стандартную структуру папок, работать перестанут…
дженериковские экшн-линки лично мне нравятся больше, чем T4MVC (и использую я их), поэтому насчет работоспособности T4MVC ничего сказать к сожалению не могу.

Но T4MVC — это тот же MvcContrib, так что не исключено, что какой-то workaround таки есть.
Ну T4MVC — это больше, чем строго-типизированные ActionLink'и. Да T4MVC — вообще мировая вещь :)

Лень проверять, совместим ли T4MVC с PortableAreas, поэтому спросил на StackOverflow (разработчик T4MVC David Ebbo фолловит тег t4mvc): stackoverflow.com/questions/6659788/is-t4mvc-compatible-with-portable-actions
И еще. Псевдо-строготипизированные ActionLink'и T4MVC шустрее строготипизированных ActionLink'ов на лямбдах.
А есть ссылки на сравнения производительности? Любопытно, насколько именно лямбды медленнее.

Посмотрел подробнее на T4MVC — да, он любопытен, надо-таки попробовать.
Есть статья Phil Haack об этом. Там есть ссылка на презентацию, где на 25 слайде приводится сравнение.

Проблема строго-типизированного ActionLink'а заключается в том, что скомпилированный Expression Tree нельзя закешировать, если в Action передаются параметры. T4MVC лишен этого недостатка, потому что он эмулирует строгую типизацию (внутри все равно строки).
Ну очевидно, что разбор Expression Tree с помощью Visitor'а будет медленнее, чем просто подстановка значений.

Я сам юзал такие линки (с лямбдами), потом понял, что они не сверхъестественно удобны (ведь это только псевдо-строгая типизация, реально контроллер и экшн все равно ищутся по имени. Просто в случае лямбды, они достают это имя из Expression Tree).

Я чувствовал себя неплохо и с T4MVC, ну а строки не нравились никогда. И не из за строк как таковых, а именно из за того, что все время путаница, где название линка, где контроллер, а где экшн. Плюс Area в виде route-data-параметра.

Поэтому для себя в SmartFacade я реализовал линки с использованием динамиков. Получается вот так:

@Html.ActionLink(a => a.Home.Index(), "Go Home")
@Html.ActionLink(a => a.Blog.Edit(id: 5), "Edit blog")

или с Area:
@Html.ActionLink(a => a.MyArea.MyController.MyAction(myParam: 5, myAnotherParam: "Hello"), "My link")

или с Controller namespace:
@Html.ActionLink(a => a.Some.Controller.Name.Space.MyController.MyAction(), "Some link")
а интеллисенс в динамиках разве работает?
И в случае переименования Экшена или параметра в экшене — оно нормально отработает в вашей реализации?
Ну нет, конечно, это просто замена строк. Но не напрягает, и получается довольно читабельно. Плюс там всякие соглашения еще поддерживаются.

И еще. Не помню, когда последний раз переименовывал экшен — поэтому это никогда не было проблемой. Что касается параметров экшена — я их вообще не меняю, поскольку у меня больше одного параметра не бывает. Я использую принцип One Model In-One Model Out.
А в чем преимущества по сравнению с T4MVC? Я вижу два недостатка: отсутствие IntelliSense и ошибки в Runtime вместо Compilte-time.
Тут очень зависит от Development-flow и личных предпочтений, наверное. Я не стесняюсь использовать dynamic-типы, когда это уместно. А DynamicExpression-ссылки — это какой-то более «рельсовый» подход. Тут кому что больше нравится. View-шаблоны все равно пред- и пере-компилируются в Runtime обычно.

Насчет IntelliSense — да, тут ничего не поделаешь, но пока ни разу не пострадал от этого.

Преимущество перед T4MVC только одно — не нужно T4 и генерации :) Ну плюс, при необходимости какие-нибудь соглашения переопределить можно.
Вот эту мысль не понял: «View-шаблоны все равно пред- и пере-компилируются в Runtime обычно.»
Я и сам не понял :)
На самом деле, я имел в виду, что View-шки все равно компилируются при использовании, я так понимаю после каждого исменения. А в них постоянно что-то меняется, и ошибка компиляции хелпера сразу показывается. В общем, я бы не стал делать что-то, если бы оно мне лично не было бы удобно и с этой реализацией проблем не было (как впрочем, не было и с T4MVC, но тут кому что ближе).

P.S. Я сначала сам был только «за строгую типизацию, это же C#, не нужно делать из ASP.NET MVC еще один RoR». А сейчас как-то по-другому смотрю на вещи, и если задача того стоит — можно использовать и динамики, и loose-контракты, и уж тем более динамические хелперы.
>>View-шки все равно компилируются при использовании

Так фишка в том, что вы не получите ошибку на этапе компиляции, а лишь в рантайме при открытии страницы. А это ооочень плохо.

>>В общем, я бы не стал делать что-то, если бы оно мне лично не было бы удобно и с этой реализацией проблем не было

Интересно :) Все мы действуем лишь в рамках наших текущих знаний. И то, что кажется удобным, может оказаться унылым говном.

>> если задача того стоит — можно использовать и динамики

Если стоит — безусловно. Но в приведенном вами случае считаю, что оно того не стоит. Те же недостатки, что и у обычных строк, так еще и работает медленнее вдобавок (dynamic использует пусть и оптимизированный, но все же reflection).
Jeremy Miller правильно говорил насчет opinionated-софта. И моя реализация — ооочень opinionated. То есть, я никого не вынуждаю использовать именно ее :)

Насчет текущих знаний и унылого говна.
Я читал ваши статьи и вижу, что вы хороший спец по теме, а не школьник, который не знает о чем говорит или не знает других методов, но и я не первый день на родео :)
Тут могу только сказать, что попробовал все возможные подходы, чтобы понять, какой именно мне наиболее комфортен.
Сам проект для PortableArea такой-же обычный проект MVC, никаких вопросов не возникло с внедрением в него T4 и использованием Resources, Templates (i.e. EditorFor) и другого встроенного функционала.
А автор T4MVC признает проблемы :)
Любопытно, как у вас получилось всё хорошо. У меня тоже были проблемы с тем, что структура проекта, требуемая Portable Areas не совпадает с требованиями T4MVC. В итоге небольшой патчик на T4MVC решил проблему, но у вас, видимо, было как-то по-другому. Поделитесь?
Понял, что вы имели ввиду, Да, вы правы в этои связке не работает. я не использую T4MVC Contrib для генерации путей. T4 (In general) использовался только как scaffolding for models.
«Небольшой патчик» включен в T4MVC
«Респект и уважуха» за то, что не поленился и довел до конца :)

Если кто-то захочет воспользоваться, то новая версия доступна под ревизией 51feba67b023 здесь
Четсно говоря, такая свистопляска с embedded ресурсами выглядит как нездоровый костыль
Это издержки того, что библиотека получается «цельной».
То есть чтобы её использовать достаточно просто подключить в проект один файл, и не требуется таскать за собой вьюшки.

В некоторых случаях это может быть неудобно, да. Но плюсы «цельности» для меня лично перевешивают.
Цельность — хорошо. Reusability — тоже. Такая задача есть на самом деле. Но именно текущая реализация с Portable Areas — не лучшее. Сам думаю, как можно сделать это лучше.
А какие именно минусы вы видите в Portable Area как таковых? То есть какие именно моменты есть желание улучшить?
Мне не нравятся лишние «телодвижения» для тривиальных вещей и немного смущает необходимость внедрения ресурсов. Я думаю, как это можно сделать с помощью соглашений, с помощью discovery и более «автоматическим».

Так же как, я не использую AreaRegistrationContext для регистрации Areas — они регистрируются автоматически. Хотелось бы сделать аналогичным образом. С другой стороны «portable»-ности действительно может и не получиться без подхода с внедрением ресурсов.
А в чем преимущества по сравнению с T4MVC? Я вижу два недостатка: отсутствие IntelliSense и ошибки в Runtime вместо Compilte-time.
Я активно использую эту библиотеку в своем проекте, есть два варианта включения ресурсов, можно просто копировать их в Area папку и MVC найдет ресурсы сам.
В свое время очень много ресурсов прошерстил придумывая модульность проекта на .NET (очень уж мне импонировала структура WordPress), идеал из доступных .NET проектов сейчас для меня orchardproject.net как раз сейчас вникаю в структуру и код, очень нравится как грамотно там все сделали. Так же похожий принцип реализован в другом начинающем опен сорс проекте: core framework (github.com/coreframework/Core-Framework). Там ребята реализовали динамическую загрузку модулей используя MEF (Managed Extensibility Framework).

Если у кого будут еще ссылки на похожие проекты, поделитесь плз, буду весьма благодарен
Можете взглянуть на мою игрушку.
Тоненький слой поверх MVC, все ищет и подключает сам (концептуально — что-то вроде MEF — это хорошая вещь, позволяет внедрять соглашения).

P.S. Надо про него статью написать, что ли :)
Эх, если бы я наткнулся на эту статью раньше.
Перечитал десяток статей, так люди делают это через жо ТАКОЕ, а мне надо было лишь вынести админку.
В итоге решение сам нашел, но время потерял.
Sign up to leave a comment.

Articles