Comments 76
Во-первых, с самого начала возникла необходимость из шаблона обращаться к методам основного объекта веб-приложения (назовем его Main) — например, конфигурация, менеджер тем, к методам вызывающего контроллера и так далее.
По MVC-шной идеологии в норме не должно быть необходимости из View обращаться к внешним ресурсам — вьюшка получает модель со всем необходимым. Я не прав? :)
ControlHelper — он реализован как свойство базовой страницы для удобства использования? Это не набор статических по сути хэлперов?
Про разметку МастерПейджФайла тегами, к сожалению, не понял идею. Возможно, потому что апологет Razor'a… :)
+6
Вы всегда точно знаете, где у вас лежит MasterPage? Или же параметр все-таки может зависеть от настроек, от выбранной темы, от выбранного стиля, от фазы луны....?
0
«Во-первых, с самого начала возникла необходимость из шаблона обращаться к методам основного объекта веб-приложения (назовем его Main) — например, конфигурация, менеджер тем, к методам вызывающего контроллера и так далее.»
В этот момент вы и нарушили MVC. Дальше можно не читать.
Все, что представлению нужно, должно быть во (вью)модели.
В этот момент вы и нарушили MVC. Дальше можно не читать.
Все, что представлению нужно, должно быть во (вью)модели.
+3
Подскажите, как View узнает текущую тему или например имя пользователя и его роли?
+1
Model.CurrentTheme
Model.User.Name
Model.User.Roles
(последнее, кстати, View знать не надо в 98% случаев)
Model.User.Name
Model.User.Roles
(последнее, кстати, View знать не надо в 98% случаев)
0
Это значит надо каждый раз во View передавать значения этих полей? т.е. сделать базовый класс для всех моделей?
0
«Это значит надо каждый раз во View передавать значения этих полей? т.е. сделать базовый класс для всех моделей?»
Несколько вариантов решения:
— базовый класс для всех моделей
— дженерик-класс для моделей (это чище с точки зрения семантики)
— инъекция дополнительной модели во viewbag на уровне фильтра и простенький хелпер, который ее оттуда достает (самое семантически чистое решение, но чуть более грязный код)
«Почему же. В зависимости от ролей показывать те или иные ссылки, части страницы и данные (в одном представлении). Это про Roles „
Это классическая ошибка при разделении обязанностей. В идеальном view нет ни одного if, в реальных view if опираются на данные представления (“надо показать»), а не бизнес-логику («если пользователь — админ»).
Надо показать разные данные? Отфильтруйте данные в контроллере.
Надо показать разные ссылки (меню)? Положите меню в модель и меняйте в контроллере.
Надо показать разные части страницы? Сделайте в модели признаки класса ShowEditToolbar и опирайтесь на них, а не на User.Roles.Contains(«Admin»)
Несколько вариантов решения:
— базовый класс для всех моделей
— дженерик-класс для моделей (это чище с точки зрения семантики)
— инъекция дополнительной модели во viewbag на уровне фильтра и простенький хелпер, который ее оттуда достает (самое семантически чистое решение, но чуть более грязный код)
«Почему же. В зависимости от ролей показывать те или иные ссылки, части страницы и данные (в одном представлении). Это про Roles „
Это классическая ошибка при разделении обязанностей. В идеальном view нет ни одного if, в реальных view if опираются на данные представления (“надо показать»), а не бизнес-логику («если пользователь — админ»).
Надо показать разные данные? Отфильтруйте данные в контроллере.
Надо показать разные ссылки (меню)? Положите меню в модель и меняйте в контроллере.
Надо показать разные части страницы? Сделайте в модели признаки класса ShowEditToolbar и опирайтесь на них, а не на User.Roles.Contains(«Admin»)
+5
>> В идеальном view нет ни одного if
а если вам нужно разным цветом строчку в табличке нарисовать в зависимости от статуса? неужели цвет из контроллера передавать будите или всеже @helper метод?
а если вам нужно разным цветом строчку в табличке нарисовать в зависимости от статуса? неужели цвет из контроллера передавать будите или всеже @helper метод?
0
В идеальном случае — буду передавать цвет. В неидеальном — использовать функцию GetColorByStatus.
0
я бы второй сценарий посчитал более «идеальным». в нем вопросы предствления данных решает только ViewEngine
представьте сбебе тесты контроллера по первому сценарию, или задачу по редизайну, которая приводит к изменению свойств модели данных
представьте сбебе тесты контроллера по первому сценарию, или задачу по редизайну, которая приводит к изменению свойств модели данных
0
«представьте сбебе тесты контроллера по первому сценарию, или задачу по редизайну, которая приводит к изменению свойств модели данных „
Легко и непринужденно. А вот представьте себе автоматическое тестирование, что что нужная строчка действительно отображается нужным цветом, при втором сценарии?
Легко и непринужденно. А вот представьте себе автоматическое тестирование, что что нужная строчка действительно отображается нужным цветом, при втором сценарии?
0
сценарии тестирования UI — отдельная песня. лично я не склонен их автоматизировать, но даже если так, то данный кейс должен проверятся именно «там».
контроллер не в курсе, кто и как будет представлять модель данных пользователю. возьмем, например, другой ViewEngine который вместо рендеринга html будет поросто возвращать модель в xml или json. зачем нам тут свойство «цвет»?
контроллер не в курсе, кто и как будет представлять модель данных пользователю. возьмем, например, другой ViewEngine который вместо рендеринга html будет поросто возвращать модель в xml или json. зачем нам тут свойство «цвет»?
0
«контроллер не в курсе, кто и как будет представлять модель данных пользователю»
Это как?
Вот как раз контроллер-то и в курсе, больше некому. Именно контроллер говорит, что возвращать — View или Json или НашГениальныйActionResult.
«зачем нам тут свойство «цвет»»
Потому что в приведенном примере оно является частью бизнес-логики.
Вообще же мы тут вступаем на зыбкую почву деления логики на представление и бизнес, и там однозначные ответы бывают не очень часто.
Это как?
Вот как раз контроллер-то и в курсе, больше некому. Именно контроллер говорит, что возвращать — View или Json или НашГениальныйActionResult.
«зачем нам тут свойство «цвет»»
Потому что в приведенном примере оно является частью бизнес-логики.
Вообще же мы тут вступаем на зыбкую почву деления логики на представление и бизнес, и там однозначные ответы бывают не очень часто.
0
>>Вот как раз контроллер-то и в курсе, больше некому. Именно контроллер говорит, что возвращать — View или Json или НашГениальныйActionResult.
View() это метод базового класса, который на основе сконфигуренного в web.config ViewEngine выполнит действие по преобразованию модели в Response для клиента. мы можем использовать любой ViewEngine, не обзязательно Razor. Такмим образом контроллер об этом не знает.
Json это наследник ActionResult который к ViewEngine не имеет отношения.
View() это метод базового класса, который на основе сконфигуренного в web.config ViewEngine выполнит действие по преобразованию модели в Response для клиента. мы можем использовать любой ViewEngine, не обзязательно Razor. Такмим образом контроллер об этом не знает.
Json это наследник ActionResult который к ViewEngine не имеет отношения.
0
«View() это метод базового класса, который на основе сконфигуренного в web.config ViewEngine выполнит действие по преобразованию модели в Response для клиента. мы можем использовать любой ViewEngine, не обзязательно Razor. Такмим образом контроллер об этом не знает.»
Говоря «View» контроллер _ожидает_, что там будет именно представление. А раз представление — значит, цвет имеет смысл, кто и как его отрисует — вопрос пятнадцатый.
«Json это наследник ActionResult который к ViewEngine не имеет отношения. „
Не вы ли написали: “другой ViewEngine который вместо рендеринга html будет поросто возвращать модель в xml или json»?
Вот именно чтобы не нарушать семантику и очевидность происходящего не надо писать такие viewengine.
Говоря «View» контроллер _ожидает_, что там будет именно представление. А раз представление — значит, цвет имеет смысл, кто и как его отрисует — вопрос пятнадцатый.
«Json это наследник ActionResult который к ViewEngine не имеет отношения. „
Не вы ли написали: “другой ViewEngine который вместо рендеринга html будет поросто возвращать модель в xml или json»?
Вот именно чтобы не нарушать семантику и очевидность происходящего не надо писать такие viewengine.
0
>> Говоря «View» контроллер _ожидает_, что там будет именно представление. А раз представление — значит, цвет имеет смысл, кто и как его отрисует — вопрос пятнадцатый.
настоящий контроллер ожидает что метод View() вернет наследника ActionResult, а кто там ему что в респонс напишет — определяется в конфигурации приложения.
>>Не вы ли написали: “другой ViewEngine который вместо рендеринга html будет поросто возвращать модель в xml или json»?
я решал подобную задачу (делал restful сервис) но там я вообще выкинул все ViewEngine и написал своего наследника ActionResult, который в зависимости от заголовков в реквесте формировал респонс в правильном формате.
мы с вами расходимся в тезисе, что свойство «цвет строчки в таблице» является частью бизнес логики. тут уж ничего не поделать.
настоящий контроллер ожидает что метод View() вернет наследника ActionResult, а кто там ему что в респонс напишет — определяется в конфигурации приложения.
>>Не вы ли написали: “другой ViewEngine который вместо рендеринга html будет поросто возвращать модель в xml или json»?
я решал подобную задачу (делал restful сервис) но там я вообще выкинул все ViewEngine и написал своего наследника ActionResult, который в зависимости от заголовков в реквесте формировал респонс в правильном формате.
мы с вами расходимся в тезисе, что свойство «цвет строчки в таблице» является частью бизнес логики. тут уж ничего не поделать.
0
«настоящий контроллер ожидает что метод View() вернет наследника ActionResult, а кто там ему что в респонс напишет — определяется в конфигурации приложения.»
Тем не менее, написать туда должны именно представление. Смысл всей этой операции именно такой.
«я решал подобную задачу (делал restful сервис) но там я вообще выкинул все ViewEngine и написал своего наследника ActionResult, который в зависимости от заголовков в реквесте формировал респонс в правильном формате.»
Вы решали совершенно другую задачу, которая вообще к MVC отношения не имеет.
Тем не менее, написать туда должны именно представление. Смысл всей этой операции именно такой.
«я решал подобную задачу (делал restful сервис) но там я вообще выкинул все ViewEngine и написал своего наследника ActionResult, который в зависимости от заголовков в реквесте формировал респонс в правильном формате.»
Вы решали совершенно другую задачу, которая вообще к MVC отношения не имеет.
0
>>Тем не менее, написать туда должны именно представление. Смысл всей этой операции именно такой.
это ваше личное мнение, которое к MVC отношения не имеет )
это ваше личное мнение, которое к MVC отношения не имеет )
0
То есть семантика слова View, ViewResult и ViewEngine (а так же их «случайное» совпадение с V из триады MVC) — это мое личное мнение, а не банальный английский язык?
Bad design, что я могу сказать. МакКоннел в таких местах очень ругается. Если я пишу return new ViewResult() — то я возвращаю представление, так явно написано в коде, и противоречить этому нехорошо и не стоит.
(Вот то, как это представление генерится, что в реальности там отдается — html, который отобразится браузером, или json для клиентского шаблона, который взаимодействует с кастомным viewengine — дело пятое.)
Не надо в стремлении к универсальности нарушать прозрачность понимания кода.
Bad design, что я могу сказать. МакКоннел в таких местах очень ругается. Если я пишу return new ViewResult() — то я возвращаю представление, так явно написано в коде, и противоречить этому нехорошо и не стоит.
(Вот то, как это представление генерится, что в реальности там отдается — html, который отобразится браузером, или json для клиентского шаблона, который взаимодействует с кастомным viewengine — дело пятое.)
Не надо в стремлении к универсальности нарушать прозрачность понимания кода.
0
>>То есть семантика слова View, ViewResult и ViewEngine (а так же их «случайное» совпадение с V из триады MVC) — это мое личное мнение, а не банальный английский язык?
View не обязательно то, что умеет отображать цвета и представляется html'ом. представление в общем случае может быть любым.
если вы считаете «цвет строчки в табличке» данными приложения, а не параметром представления — я с вами никак не могу согласиться.
View не обязательно то, что умеет отображать цвета и представляется html'ом. представление в общем случае может быть любым.
если вы считаете «цвет строчки в табличке» данными приложения, а не параметром представления — я с вами никак не могу согласиться.
0
«View не обязательно то, что умеет отображать цвета и представляется html'ом. представление в общем случае может быть любым.»
Тем не мене, это именно представление. Поэтому ваш комментарий про «это ваше личное мнение, которое к MVC отношения не имеет» как-то не к месту.
«если вы считаете «цвет строчки в табличке» данными приложения, а не параметром представления — я с вами никак не могу согласиться. „
Это может быть данными приложения как минимум в двух случаях: это записывается пользователем (настраиваемый интерфейс), и этот цвет напрямую зависит от бизнес-логики.
Конечно, лучше абстрагировать цвета через признаки. Но это не всегда удается.
Тем не мене, это именно представление. Поэтому ваш комментарий про «это ваше личное мнение, которое к MVC отношения не имеет» как-то не к месту.
«если вы считаете «цвет строчки в табличке» данными приложения, а не параметром представления — я с вами никак не могу согласиться. „
Это может быть данными приложения как минимум в двух случаях: это записывается пользователем (настраиваемый интерфейс), и этот цвет напрямую зависит от бизнес-логики.
Конечно, лучше абстрагировать цвета через признаки. Но это не всегда удается.
0
напомню изначальный сценарий:
>>а если вам нужно разным цветом строчку в табличке нарисовать в зависимости от статуса? неужели цвет из контроллера передавать будите?
ваш ответ был утвердительным.
вы согласны с тезисом, что передавать значение цвета элемена UI из контроллера — есть нарушение принципа разделения ответственности в MVC приложении как бы удобно это не выглядело?
>>а если вам нужно разным цветом строчку в табличке нарисовать в зависимости от статуса? неужели цвет из контроллера передавать будите?
ваш ответ был утвердительным.
вы согласны с тезисом, что передавать значение цвета элемена UI из контроллера — есть нарушение принципа разделения ответственности в MVC приложении как бы удобно это не выглядело?
0
«ваш ответ был утвердительным.»
Это не так, я указал два варианта ответа.
«вы согласны с тезисом, что передавать значение цвета элемена UI из контроллера — есть нарушение принципа разделения ответственности в MVC приложении как бы удобно это не выглядело?»
Нет, не согласен. Потому что это «в зависимости от статуса». Зависимость чего-то от статуса вполне может быть бизнес-логикой. А бизнес-логике не место в представлении.
Вы, надеюсь, помните, что в asp.net mvc M — не чистая модель, а viewmodel, то есть view-specific data?
Это не так, я указал два варианта ответа.
«вы согласны с тезисом, что передавать значение цвета элемена UI из контроллера — есть нарушение принципа разделения ответственности в MVC приложении как бы удобно это не выглядело?»
Нет, не согласен. Потому что это «в зависимости от статуса». Зависимость чего-то от статуса вполне может быть бизнес-логикой. А бизнес-логике не место в представлении.
Вы, надеюсь, помните, что в asp.net mvc M — не чистая модель, а viewmodel, то есть view-specific data?
0
еще маленький пример. представьте что нужно передать не цвет, а много всего (размеры, отступы, цвета, шрифты). вам сразу же захочется передавать это все одним css классом (иначе html будет уныл). если так, то у вас появляется зависимость логики от представления со всеми вытекающими.
0
«представьте что нужно передать не цвет, а много всего (размеры, отступы, цвета, шрифты).»
С трудом себе это представляю.
Тем не менее, если это зависит от какой-то бизнес-логики («если автор сообщения такой-то, то делать так»), то корректно выносить это из представления выше, чтобы это было тестируемо. Можно прямо в контроллер, можно в промежуточный фильтр.
Но чаще всего это вырождается в следующее: отображаемые объекты (например, письма) имеют признаки (например: непрочитанные, личные, важные). Допустимо (хотя и противоречит пуристскому подходу) писать во view код следующего толка:
if (message.IsImportant) {сделать жирным}
if (message.IsPersonal) {добавить иконку}
Но вот писать там же
if (message.Size > 15M) {нарисовать иконку гири}
уже не стоит.
Грань очень тонкая, на самом деле.
С трудом себе это представляю.
Тем не менее, если это зависит от какой-то бизнес-логики («если автор сообщения такой-то, то делать так»), то корректно выносить это из представления выше, чтобы это было тестируемо. Можно прямо в контроллер, можно в промежуточный фильтр.
Но чаще всего это вырождается в следующее: отображаемые объекты (например, письма) имеют признаки (например: непрочитанные, личные, важные). Допустимо (хотя и противоречит пуристскому подходу) писать во view код следующего толка:
if (message.IsImportant) {сделать жирным}
if (message.IsPersonal) {добавить иконку}
Но вот писать там же
if (message.Size > 15M) {нарисовать иконку гири}
уже не стоит.
Грань очень тонкая, на самом деле.
0
я бы делал это так
@helper GetMessage(MyMessage msg)
{
if(msg.Size > 15)
{
<img картинка с гирей
}
if (msg.IsImportant)
{
<span class=жирно и красиво @msg.Text</span
}
else
{
@msg.Text
}
}
и далее во View там, где нужно нарисовать сообщение, вызываем наш хелпер метод:
@GetMessage(item)
в приведенном вами примере нет бизнес логики.
@helper GetMessage(MyMessage msg)
{
if(msg.Size > 15)
{
<img картинка с гирей
}
if (msg.IsImportant)
{
<span class=жирно и красиво @msg.Text</span
}
else
{
@msg.Text
}
}
и далее во View там, где нужно нарисовать сообщение, вызываем наш хелпер метод:
@GetMessage(item)
в приведенном вами примере нет бизнес логики.
0
Может быть подскажите Best Practices с использованием правильного MVC? Понятно, что бизнес логика должна быть в контроллере (или в сервисах) еще подумаю на сложными задачами. Но хотелось бы посмотреть реальный пример, как это все работает, а не на пример из коробки где все просто.
0
опс, неверно понял смысл с первого раза.
>> в реальных view if опираются на данные представления (“надо показать»), а не бизнес-логику («если пользователь — админ»).
вобщем да — все так.
>> в реальных view if опираются на данные представления (“надо показать»), а не бизнес-логику («если пользователь — админ»).
вобщем да — все так.
0
Почему же. В зависимости от ролей показывать те или иные ссылки, части страницы и данные (в одном представлении). Это про Roles
0
Логику относительно разных ролей контроллер должен обрабатывать.
0
Логику — да, а представление (что показать а что нет). Вот синтетический пример: админу нужно показать курс валюты $/евро, а пользователю — $/руб. Решение — дополнительное поле в Model?
0
Есть такая штука для ролей: User.IsInRole(«Admin»)
-1
Какое-то все у вас не MVCшное.
Может не вник, но ViewModel не пробовали поделать под ваши нужды?
Разделения ответственности у вас в приложении получается, что нету.
Может не вник, но ViewModel не пробовали поделать под ваши нужды?
Разделения ответственности у вас в приложении получается, что нету.
+1
>> с самого начала возникла необходимость из шаблона обращаться к методам основного объекта веб-приложени
Как уже было отмечено, вы концептуально нарушаете паттерн MVC
>>Стандартный класс System.Web.Mvc.ViewPage не предоставляет удобного функционала для этого
зато есть HtmlHelper и куча расширений к нему. в вашем случае можно использовать Html.RenderAction для вынесения всей логики по вызову «объекта Main» в контроллер.
Как уже было отмечено, вы концептуально нарушаете паттерн MVC
>>Стандартный класс System.Web.Mvc.ViewPage не предоставляет удобного функционала для этого
зато есть HtmlHelper и куча расширений к нему. в вашем случае можно использовать Html.RenderAction для вынесения всей логики по вызову «объекта Main» в контроллер.
+1
И еще.
«Во-вторых, возникла необходимость в представлениях не задавать прямой путь MasterPageFile, а размечать его дополнительными тегами а-ля «CurrentTheme.SiteMaster», «UserTheme.SiteMaster» и т.п. К сожалению, при записи подобной строки в атрибут MasterPageFile директивы @Page я получал ошибку синтаксического анализатора, ругавшегося на отсутствие файла „~/Views/{CurrentTheme.SiteMaster}“. Единственное найденное решение — создание своего атрибута для директивы @Page, например MasterPagePath»
В Razor это делается напрямую — в Layout можно писать что угодно. В WebForms такие штуки можно делать что на уровне action — просто отдавая View с указанием нужного мастерпейджа, что на уровне actionfilter, записывая MasterName, что написав собственный ViewEngine.
codeofrob.com/archive/2009/11/01/dynamically-switching-between-master-pages-in-asp.net-mvc.aspx
«Во-вторых, возникла необходимость в представлениях не задавать прямой путь MasterPageFile, а размечать его дополнительными тегами а-ля «CurrentTheme.SiteMaster», «UserTheme.SiteMaster» и т.п. К сожалению, при записи подобной строки в атрибут MasterPageFile директивы @Page я получал ошибку синтаксического анализатора, ругавшегося на отсутствие файла „~/Views/{CurrentTheme.SiteMaster}“. Единственное найденное решение — создание своего атрибута для директивы @Page, например MasterPagePath»
В Razor это делается напрямую — в Layout можно писать что угодно. В WebForms такие штуки можно делать что на уровне action — просто отдавая View с указанием нужного мастерпейджа, что на уровне actionfilter, записывая MasterName, что написав собственный ViewEngine.
codeofrob.com/archive/2009/11/01/dynamically-switching-between-master-pages-in-asp.net-mvc.aspx
+2
А зачем потребовалось создавать ViewTypeParserFilter? Я точно помню, что в asp.net mvc совершенно аналогичный класс был. Собственно поэтому там обобщённые типы в aspx-, ascx-, master- файлах там и так работали.
0
Господа, а статья-то отличная.
Пример не сильно удачный, с построением связи из View -> Controller
Да, действительно, View ни чего не должна «знать» о контроллере.
А статья отличная, т.к. показывает как можно сделать следующее:
— View.cshtml —
Предположим, у нас был сайт, и рано или поздно кто-то захотел сделать CMS и менять какие-то блоки.
Можно сделать два подхода:
@Html.Placeholder(Model.Placeholder1)
@Html.Placeholder(Model.Placeholders, «placeholderName»)
А можно использовать эту статью, и просто в те, места что можно переопределять добавить дополнительный аттрибут и просто уже в рантайме засунуть туда нужный контент.
Есть и 4й более сложный способ — это переопределить RenderingEngine, но там очень много нужно сделать.
Автору зачёт.
Пример не сильно удачный, с построением связи из View -> Controller
Да, действительно, View ни чего не должна «знать» о контроллере.
А статья отличная, т.к. показывает как можно сделать следующее:
— View.cshtml —
Предположим, у нас был сайт, и рано или поздно кто-то захотел сделать CMS и менять какие-то блоки.
Можно сделать два подхода:
@Html.Placeholder(Model.Placeholder1)
@Html.Placeholder(Model.Placeholders, «placeholderName»)
А можно использовать эту статью, и просто в те, места что можно переопределять добавить дополнительный аттрибут и просто уже в рантайме засунуть туда нужный контент.
Есть и 4й более сложный способ — это переопределить RenderingEngine, но там очень много нужно сделать.
Автору зачёт.
+2
Каждую конкретную проблему класса «что-то переопределить в представлении в рантайме» всегда можно решить намного проще, чем «дополнительным атрибутом».
Приведите конкретный пример — и вам расскажут, как это сделать. Для master page уже рассказали.
asp.net mvc, удивительным образом, очень хорошо расширяемый механизм. Причем прозрачно и (по большей части) очевидно.
Приведите конкретный пример — и вам расскажут, как это сделать. Для master page уже рассказали.
asp.net mvc, удивительным образом, очень хорошо расширяемый механизм. Причем прозрачно и (по большей части) очевидно.
0
Да?
Поделитесь рассуждением на тему.
У меня есть сайт с 1К+ вьюх.
Приходит change request который, коротко, говорит:
View1 — переобределить контент div'a с id='aaa' — брать из XML/SQL/etc
View2 — переопределить span с id='bbb' и брать из…
Самый простой способ это сделать, это сделать postprocessing используя идеи описаные в этой статье.
А не хоть по 1K и более вьюх и руками проставлять @Html.Placeholder или ещё что-то.
Поделитесь рассуждением на тему.
У меня есть сайт с 1К+ вьюх.
Приходит change request который, коротко, говорит:
View1 — переобределить контент div'a с id='aaa' — брать из XML/SQL/etc
View2 — переопределить span с id='bbb' и брать из…
Самый простой способ это сделать, это сделать postprocessing используя идеи описаные в этой статье.
А не хоть по 1K и более вьюх и руками проставлять @Html.Placeholder или ещё что-то.
0
«Приходит change request который, коротко, говорит:
View1 — переобределить контент div'a с id='aaa' — брать из XML/SQL/etc
View2 — переопределить span с id='bbb' и брать из…»
Ну, вообще так делать не надо, и такие CR надо спустить нафиг. (А сам факт их наличия показывает на некоторую недостаточность модульности в системе.)
Но если вам очень хочется так сделать, то вот вам три решения:
— написать свой viewengine, который будет парсить готовый html
— перехватить глобальным фильтром на выполнение результата
— в сайт.мастере/лэйауте вбросить jq-функцию, которая сделает это на клиенте.
А в среднем, хочу сказать, что обычно когда приходит такой CR, выясняется, что нужные дивы ничем не помечены.
View1 — переобределить контент div'a с id='aaa' — брать из XML/SQL/etc
View2 — переопределить span с id='bbb' и брать из…»
Ну, вообще так делать не надо, и такие CR надо спустить нафиг. (А сам факт их наличия показывает на некоторую недостаточность модульности в системе.)
Но если вам очень хочется так сделать, то вот вам три решения:
— написать свой viewengine, который будет парсить готовый html
— перехватить глобальным фильтром на выполнение результата
— в сайт.мастере/лэйауте вбросить jq-функцию, которая сделает это на клиенте.
А в среднем, хочу сказать, что обычно когда приходит такой CR, выясняется, что нужные дивы ничем не помечены.
0
Выше я высказывала мнение, что использовать свой ViewEngine достаточно трудоёмко.
Вбросить .js функцию на клиент, это свежее решение, но не идеальное. Подумаю в выходные над ним.
Что вы имеете ввиду, когда пишите: Перехватить глобальным фильтром?
P.S. Если они ни чем не помечены, то xPath и используем расположение :)
Вбросить .js функцию на клиент, это свежее решение, но не идеальное. Подумаю в выходные над ним.
Что вы имеете ввиду, когда пишите: Перехватить глобальным фильтром?
P.S. Если они ни чем не помечены, то xPath и используем расположение :)
0
«Выше я высказывала мнение, что использовать свой ViewEngine достаточно трудоёмко.»
Вообще-то, ничем не более трудоемко, чем написать свой парсер страницы (а это именно то, что понадобится делать для подхода автора).
«Что вы имеете ввиду, когда пишите: Перехватить глобальным фильтром?»
msdn.microsoft.com/en-us/library/gg416513%28VS.98%29.aspx
«Если они ни чем не помечены, то xPath и используем расположение»
Это если вам повезло и там валидный xml.
Вообще-то, ничем не более трудоемко, чем написать свой парсер страницы (а это именно то, что понадобится делать для подхода автора).
«Что вы имеете ввиду, когда пишите: Перехватить глобальным фильтром?»
msdn.microsoft.com/en-us/library/gg416513%28VS.98%29.aspx
«Если они ни чем не помечены, то xPath и используем расположение»
Это если вам повезло и там валидный xml.
+1
> P.S. Если они ни чем не помечены, то xPath и используем расположение :)
Зачем пытаться изобрести XSLT из какого-либо другого ViewEngine'а? ;)
Зачем пытаться изобрести XSLT из какого-либо другого ViewEngine'а? ;)
0
У нас например для тем некоторые вьюхи основные переопределяются. Лежат себе в отдельной папке с теми же относительными путями. Правдо используют другой layout. Для релизации пришлось перегрузить контроллер и свой вьюэнджин.
0
Да, скорее всего я ушел от чистого MVC, но ушел осознанно, т.к. мне не нравится подход, в котором модели необходимо передавать ВСЕ данные для отображения. Имхо это ничем не отличается от php-кода вида
<?php
echo ""
if (..) echo "1"; else echo…
?>
где все жестко забито без изменений. Чтобы что-то изменить, нужно лезть в код самого приложения, малейшее изменение в модели (необходимое дизайнеру) мгновенно затрагивает программиста, от чего я и пытаюсь уйти, предоставляя дизайнеру некую свободу действий. Да, не чистый MVC. Но мы не на соревновании чистоты паттернов.
<?php
echo ""
if (..) echo "1"; else echo…
?>
где все жестко забито без изменений. Чтобы что-то изменить, нужно лезть в код самого приложения, малейшее изменение в модели (необходимое дизайнеру) мгновенно затрагивает программиста, от чего я и пытаюсь уйти, предоставляя дизайнеру некую свободу действий. Да, не чистый MVC. Но мы не на соревновании чистоты паттернов.
0
При правильно построенном mvc у дизайнера как раз полная свобода действий. Ключевое слово — правильно построенном.
Просто не надо путать дизайн и бизнес.
Просто не надо путать дизайн и бизнес.
0
ViewModel — контракт между контроллером и View. Вы, похоже, пытаетесь сделать что-то сверх-супер-пупер-универсальное, с блэкджеком, для всех ситуаций, включая такие, чтобы «дизайнер мог править все без программиста». По опыту — ни к чему хорошему не приводит это. Получается сложно-поддерживаемый монстр в итоге. Есть задача — она очень хорошо и просто реализуется на MVC (если это веб).
А изменение в данных — это значит изменение в концепции проекта, то есть меняется сам вид данных, которые нужно показывать — логично, что нужно переделывать ViewModel. А если у вас на форме новое поле, вы тоже хотите без участия программиста это решать, силами дизайнера?
А изменение в данных — это значит изменение в концепции проекта, то есть меняется сам вид данных, которые нужно показывать — логично, что нужно переделывать ViewModel. А если у вас на форме новое поле, вы тоже хотите без участия программиста это решать, силами дизайнера?
0
Я так понимаю, что на вопросы по существу вам отвечать не хочется?
0
Вы уточните вопрос, на который ответ нужен.
0
Зачем вы это делаете (нарушаете паттерн, влезаете внутрь страницы для обработки masterpage, когда есть существенно более простые способы это сделать) и какую именно задачу вы пытаетесь решить?
0
приведу очень простую схему, которая используется в некоторых форумных движках:
Есть выбранная по-умолчанию тема сайта, есть тема, выбранная пользователем. Index.aspx не знает о том, какая тема выбрана, ему знать это и не надо. Ему автоматом подставляется нужный masterpage итоговой темы.
Пример 2. Есть основная тема сайта, есть маленькая «дочерняя» тема, которая отличается от основной только стилями Css и изображениями (к примеру), выходит некое наследование тем. Невозможно каждый путь к изображениям заключать в placeholder-ы, а стандартные Skin И Theme ASP.NET могут не устраивать по функционалу. В таком случае пути к ресурсам тем (например, картинка /Theme/Main/Images/Logo.jpg в masterpage прописывается как {ThemePath}/Images/Logo.jpg. Хелпер возвращает путь /Theme/Main/Images/Logo.jpg для основной темы, и /Theme/MainBlack/Images/Logo.jpg для дочерней.
Пример 3. У меня реализованы информационные блоки в представлениях. Грубо говоря, это отдельный usercontrol, с шапкой и телом, например как блок «Информация о блоге» в верхней части этой страницы. Виджеты дизайнер волен вставлять на странице в любую точку. Но нюанс в том, что виджеты могут быть разные от темы к теме, они могут блокироваться на определенных страницах. Обращаться к ним следует так <%=Helper.Widget(«name»)%>. Как предложите реализовывать их стандартными средствами, через зарегистрированный UserControl? А где тогда тут MVC? виджет это собственный маленький MVC, где Controller=объект виджета, View=представление для виджета, Model — отдельная модель для взаимодействия виджета и его представления.
Нюансов море, я еще не сделал и половины работы, но стандартные средства меня не устроили. А вот вы предложите вариант парсинга такого тегированного MasterPageFile с помощью кастомного Viewengine.
Есть выбранная по-умолчанию тема сайта, есть тема, выбранная пользователем. Index.aspx не знает о том, какая тема выбрана, ему знать это и не надо. Ему автоматом подставляется нужный masterpage итоговой темы.
Пример 2. Есть основная тема сайта, есть маленькая «дочерняя» тема, которая отличается от основной только стилями Css и изображениями (к примеру), выходит некое наследование тем. Невозможно каждый путь к изображениям заключать в placeholder-ы, а стандартные Skin И Theme ASP.NET могут не устраивать по функционалу. В таком случае пути к ресурсам тем (например, картинка /Theme/Main/Images/Logo.jpg в masterpage прописывается как {ThemePath}/Images/Logo.jpg. Хелпер возвращает путь /Theme/Main/Images/Logo.jpg для основной темы, и /Theme/MainBlack/Images/Logo.jpg для дочерней.
Пример 3. У меня реализованы информационные блоки в представлениях. Грубо говоря, это отдельный usercontrol, с шапкой и телом, например как блок «Информация о блоге» в верхней части этой страницы. Виджеты дизайнер волен вставлять на странице в любую точку. Но нюанс в том, что виджеты могут быть разные от темы к теме, они могут блокироваться на определенных страницах. Обращаться к ним следует так <%=Helper.Widget(«name»)%>. Как предложите реализовывать их стандартными средствами, через зарегистрированный UserControl? А где тогда тут MVC? виджет это собственный маленький MVC, где Controller=объект виджета, View=представление для виджета, Model — отдельная модель для взаимодействия виджета и его представления.
Нюансов море, я еще не сделал и половины работы, но стандартные средства меня не устроили. А вот вы предложите вариант парсинга такого тегированного MasterPageFile с помощью кастомного Viewengine.
0
«Есть выбранная по-умолчанию тема сайта, есть тема, выбранная пользователем. Index.aspx не знает о том, какая тема выбрана, ему знать это и не надо. Ему автоматом подставляется нужный masterpage итоговой темы.»
Для этого masterpage, как уже писалось выше, можно передавать из контроллера, подставлять в глобальном фильтре, подставлять во viewengine. Ничего из того, что вы делаете, не нужно.
«В таком случае пути к ресурсам тем (например, картинка /Theme/Main/Images/Logo.jpg в masterpage прописывается как {ThemePath}/Images/Logo.jpg. Хелпер возвращает путь /Theme/Main/Images/Logo.jpg для основной темы, и /Theme/MainBlack/Images/Logo.jpg для дочерней.»
Данные по теме пишутся во viewbag (инъекцией в глобальном фильтре), дальше пишется один хелпер, который достает эти данные (синтаксисом Html.Theme().Path), дальше эти данные *явно* используются в странице (т.е., для генерации пути к картинке делается Url.Content(string.Format("{0}/Images/Logo.jpg", Html.Theme().Path)).
«виджет это собственный маленький MVC, где Controller=объект виджета, View=представление для виджета, Model — отдельная модель для взаимодействия виджета и его представления.»
Я не очень понимаю, что вы имеете в виду под «Controller=объект виджета» (и думаю, что здесь можно обойтись обычным html helper), но обычно когда надо такое сделать (использовать отдельную mvc-триаду), берут Html.RenderAction(), который осуществляет полную обработку запроса (контроллер-действие-вывод). Ну и никто не мешает сделать Html.Widget(«name»), который внутри себя спрячет то, что нужно.
Видите? Все сделано стандартными средствами, без какого-либо тегирования.
Для этого masterpage, как уже писалось выше, можно передавать из контроллера, подставлять в глобальном фильтре, подставлять во viewengine. Ничего из того, что вы делаете, не нужно.
«В таком случае пути к ресурсам тем (например, картинка /Theme/Main/Images/Logo.jpg в masterpage прописывается как {ThemePath}/Images/Logo.jpg. Хелпер возвращает путь /Theme/Main/Images/Logo.jpg для основной темы, и /Theme/MainBlack/Images/Logo.jpg для дочерней.»
Данные по теме пишутся во viewbag (инъекцией в глобальном фильтре), дальше пишется один хелпер, который достает эти данные (синтаксисом Html.Theme().Path), дальше эти данные *явно* используются в странице (т.е., для генерации пути к картинке делается Url.Content(string.Format("{0}/Images/Logo.jpg", Html.Theme().Path)).
«виджет это собственный маленький MVC, где Controller=объект виджета, View=представление для виджета, Model — отдельная модель для взаимодействия виджета и его представления.»
Я не очень понимаю, что вы имеете в виду под «Controller=объект виджета» (и думаю, что здесь можно обойтись обычным html helper), но обычно когда надо такое сделать (использовать отдельную mvc-триаду), берут Html.RenderAction(), который осуществляет полную обработку запроса (контроллер-действие-вывод). Ну и никто не мешает сделать Html.Widget(«name»), который внутри себя спрячет то, что нужно.
Видите? Все сделано стандартными средствами, без какого-либо тегирования.
0
«Для этого masterpage, как уже писалось выше, можно передавать из контроллера, подставлять в глобальном фильтре, подставлять во viewengine. Ничего из того, что вы делаете, не нужно.»
Контроллеру абсолютно ничего не нужно знать про тему и про masterpage. Возможно, дизайнер вообще отказался от использования masterpage в данном представлении и он не нужен, а контроллер продолжает передавать ему ненужную информацию.
«Данные по теме пишутся во viewbag (инъекцией в глобальном фильтре), дальше пишется один хелпер, который достает эти данные (синтаксисом Html.Theme().Path), дальше эти данные *явно* используются в странице (т.е., для генерации пути к картинке делается Url.Content(string.Format(»{0}/Images/Logo.jpg", Html.Theme().Path))."
опять же во ViewBag писать нужно из контроллера. Контроллер не должен знать про тему.
насчет виджета да, варианты есть, не спорю. Можно вообще сделать свой server control и работать так: />.
Контроллеру абсолютно ничего не нужно знать про тему и про masterpage. Возможно, дизайнер вообще отказался от использования masterpage в данном представлении и он не нужен, а контроллер продолжает передавать ему ненужную информацию.
«Данные по теме пишутся во viewbag (инъекцией в глобальном фильтре), дальше пишется один хелпер, который достает эти данные (синтаксисом Html.Theme().Path), дальше эти данные *явно* используются в странице (т.е., для генерации пути к картинке делается Url.Content(string.Format(»{0}/Images/Logo.jpg", Html.Theme().Path))."
опять же во ViewBag писать нужно из контроллера. Контроллер не должен знать про тему.
насчет виджета да, варианты есть, не спорю. Можно вообще сделать свой server control и работать так: />.
0
«Возможно, дизайнер вообще отказался от использования masterpage в данном представлении и он не нужен, а контроллер продолжает передавать ему ненужную информацию.»
Тогда — переходите на razor, где layout задается императивно (и опирайтесь на тот же Html.Theme()). Ноль проблем.
(Но вообще вы только что дали дизайнеру феерическую возможность выстрелить себе в ногу: выбрать мастер-пейдж, а потом подменить за него этот мастер-пейдж, чтобы получить несочетаемое. Так делать… не принято, скажем так.)
«опять же во ViewBag писать нужно из контроллера»
Я же написал: инъекцией в глобальном фильтре. Контроллер тут не при чем.
«Можно вообще сделать свой server control»
В asp.net mvc нет серверных контролов. Ну нет. Вообще. Модель не предусматривает.
Тогда — переходите на razor, где layout задается императивно (и опирайтесь на тот же Html.Theme()). Ноль проблем.
(Но вообще вы только что дали дизайнеру феерическую возможность выстрелить себе в ногу: выбрать мастер-пейдж, а потом подменить за него этот мастер-пейдж, чтобы получить несочетаемое. Так делать… не принято, скажем так.)
«опять же во ViewBag писать нужно из контроллера»
Я же написал: инъекцией в глобальном фильтре. Контроллер тут не при чем.
«Можно вообще сделать свой server control»
В asp.net mvc нет серверных контролов. Ну нет. Вообще. Модель не предусматривает.
0
«Я же написал: инъекцией в глобальном фильтре. Контроллер тут не при чем»
если я правильно понимаю, ViewBag это динамическая коллекция. Если в фильтре я задам ViewBag.Test = 123
а в представлении напишу
<%=ViewBag.
то после точки IntelliSence мне ничего не подставит, т.к. ViewBag заполняется в рантайме. Так?
если я правильно понимаю, ViewBag это динамическая коллекция. Если в фильтре я задам ViewBag.Test = 123
а в представлении напишу
<%=ViewBag.
то после точки IntelliSence мне ничего не подставит, т.к. ViewBag заполняется в рантайме. Так?
0
«если я правильно понимаю, ViewBag это динамическая коллекция. Если в фильтре я задам ViewBag.Test = 123
а в представлении напишу
а в представлении напишу
0
м, а смысл цитировать часть моего сообщения?
0
Парсер — лох, как любят говорить на одном малоизвестном бложике.
Так вот, ViewBag — это не динамическая коллекция, а dynamic, но за исключением этого вы правы. Соответственно, чтобы у вас не было проблем с IntelliSense и ошибками времени выполнения, и пишется хелпер Html.Theme(), который внутри себя обращается к ViewBag по нужному ключу и преобразует объект в нужный тип.
(понятно, что хелпер должен быть согласован с инъектором, но это несложно)
Так вот, ViewBag — это не динамическая коллекция, а dynamic, но за исключением этого вы правы. Соответственно, чтобы у вас не было проблем с IntelliSense и ошибками времени выполнения, и пишется хелпер Html.Theme(), который внутри себя обращается к ViewBag по нужному ключу и преобразует объект в нужный тип.
(понятно, что хелпер должен быть согласован с инъектором, но это несложно)
0
Не сложнее чем тот же дополнительный кастомный хелпер. В общем понятно, я понял о чем вы говорите, буду копать в эту сторону, но в некоторых моментах лично для меня мой подход выгоднее и удобнее.
0
Вот только он нарушает паттерн, которым вы пользуетесь. В этом и зло.
0
От этого взорвется сервер или самопроизвольно зародится линукс? Еще в самом начале обсуждения я упомянул, что это не конкурс чистоты паттернов. Да, в MVC море стандартных возможностей, но изобретение велосипеда дело изобретателя, если мозг хочет разминки и руки чешутся, никто этого запретить не может.
0
Вот только вопрос — зачем? На ASP.NET, да еще и с MVC такие «костыли» для «улучшения MVC».
-1
Хотите вы или нет, но ASP.NET MVC построена на костях классического ASP.NET
0
Да неужели? :)
MVC не построен на «классическом» ASP.NET. MVC — это абстракция вокруг ASP.NET-фреймворка, реализующая паттерн Front Controller, имеющая перед собой цель SoC (Separation of Concerns). Так называемый «классический ASP.NET» — это ASP.NET WebForms, и это просто другая абстракия вокруг «базового» ASP.NET Framework'а, реализующая другие принципы (включая паттерн Page Controller).
«Классическим» называют вебформс, так как он был единственной абстракцией вокруг ASP.NET. И MVC — это отнюдь не надстройка над WebForms.
Просто был один WebForms, а теперь на ASP.NET три фреймворка (от MS) — WebForms, MVC и WebMatrix.
MVC не построен на «классическом» ASP.NET. MVC — это абстракция вокруг ASP.NET-фреймворка, реализующая паттерн Front Controller, имеющая перед собой цель SoC (Separation of Concerns). Так называемый «классический ASP.NET» — это ASP.NET WebForms, и это просто другая абстракия вокруг «базового» ASP.NET Framework'а, реализующая другие принципы (включая паттерн Page Controller).
«Классическим» называют вебформс, так как он был единственной абстракцией вокруг ASP.NET. И MVC — это отнюдь не надстройка над WebForms.
Просто был один WebForms, а теперь на ASP.NET три фреймворка (от MS) — WebForms, MVC и WebMatrix.
0
Sign up to leave a comment.
Расширение функционала тегов Page/MasterPage/UserControl в ASP.NET MVC