2013-08-08 3 views
2

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

  1. В течение нашего периода обслуживания покажите предупреждение на каждой странице после входа пользователя.
  2. Рядом с нашим периодом обслуживания выведите предупреждение на каждой странице после того, как пользователь выполнил вход (но с другим контентом, чем # 1)
  3. В течение обычных периодов покажите сообщение только после входа, но не для последующих страниц.
  4. Вполне возможно, что я, возможно, пожелает добавить дополнительные сообщения в эту область из других мнений/контроллеров, но не хотят, чтобы сознавать ли я перекрывая предупреждения по обслуживанию

Я действительно изо всех сил с правильным способом сделать это. Сейчас у меня есть что-то вроде:

public class LayoutController : Controller 
{ 
    [ChildActionOnly] 
    public IHtmlString GetMarginMessages() { 
     loadMaintenanceMessages(); 
     var messages = this.ViewBag.MarginMessages.ToSingleString(); 
     return new HtmlString(messages); 
    } 

    private List<string> loadMaintenanceMessages() { 
     if (withinMaintenancePeriod) 
     { 
      this.ViewBag.MarginMessages.Add("foo"); 
     } 
     else if (nearMaintenancePeriod) { 
      this.ViewBag.MarginMessages.Add("bar"); 
     } 
    } 
} 

Тогда в моем макете я могу иметь:

<div id="marginMessage">@Html.Action("GetMarginMessages")</div> 

В других страницах или контроллеров, я могу иметь:

this.ViewBag.MarginMessages.Add("Something") // or have it go through a helper of sorts 

Является ли это право способ думать об этом? Я не в восторге от использования ViewBag, но я не вижу лучшего способа управления совместным доступом между контроллерами и контроллерами. И выполнение проверки времени обслуживания на каждом представлении рендеринга тоже не очень хорошо.

Какие существуют другие варианты, которые мне не хватает?

ответ

3

Для этого у меня будет раздел в представлении макета, который выполняет отдельное действие. Что-то вроде

(page stuff...) 
<div id="marginMessages> 
    Html.Action("GetMarginMessages", "Infrastructure") 
</div> 
(more page stuff...) 

, где у вас есть InfrastructureController как контроллер, который обрабатывает сквозные проблемы, такие как маржинальные сообщения, сообщения уведомления и тому подобное. Этот контроллер будет иметь метод GetMarginMessages, который определяет, нужно ли отображать сообщения, и если да, то возвращает частичный вид, содержащий эти сообщения, однако вы их хотите. Если сообщений нет, он может вернуть EmptyResult, и вы должны убедиться, что ваша страница выглядит нормально, когда div пуст.

Для получения более сложной логики, можно создать фильтр действий, полученный из ActionFilterAttribute, что ловит запрос либо после метода контроллера (OnActionExecuted()), или до того, как вид визуализирует (OnResultExecuting()). (Теоретически, не важно, какой из них вы используете.)

Оттуда вы можете использовать filterContext для:

  • посмотреть, какой способ управления и действия пользователя просто нажмите
  • увидеть, какие значения контроллера положить в модель, ViewBag и TempData
  • добавить/удалить/изменить значения в модели, ViewBag и TempData

Итак, оттуда вы сможете настроить значения, чтобы передать частичное представление части сообщения, что ему нужно сделать. Частичный вид может затем извлекать эти значения и использовать их, но он должен (просто помните, чтобы не проверять все вещи, прежде чем пытаться их использовать).

После установки, этот фильтр действие может быть применен к:

  • всех методов, путем добавления его к GlobalFilterCollection в методе Application_Start() в Global.asax.cs
  • весь контроллер, добавив его выше линия public class MyController : Controller в файле контроллера
  • специфический метод, добавив его выше этого метода

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

+0

Да, но не делает ли дополнительный запрос на каждой странице, которую вы делаете? Я имею в виду, если у вас есть помощник Html.Action в вашем макете, тогда вы эффективно запускаете другой HTTP-запрос каждый раз ... – Marko

+0

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

+0

Я думаю, что это похоже на самый логичный, удобный подход. – DuncanMack

0

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

public class BaseController : Controller 
{ 
    // This is the instance of your business logic that will figure out what messages need to be displayed based on various parameters you specify. 
    // I leave it to you to write the GetAllMessages method for the MessageService. 
    var messagesService = new MessagesService(); 
    // This is the local variable that will hold all your system messages. 
    var systemMessages = new List<SystemMessage>(); 

    protected override void Initialize(RequestContext requestContext) 
    { 
     base.Initialize(requestContext); 
     systemMessages = messageService.GetAllMessages(); 
     ViewBag.SystemMessages = systemMessages; 
    } 
} 

После этой установки они все ваши другой контроллер наследует от базового контроллера:

public class SomeController : BaseController 
{ 
    // Controller logic here... 
} 

так теперь у вас есть ваши системные сообщения, доступные вам через свойство messagesService контроллера. Кроме того, у вас есть доступ к ним через ViewBag.SystemMessages. Теперь причина этого в том, что вы можете нажать эту немного дальше, создав настраиваемое представление бритвы, как это:

namespace YourProject.Views 
{ 
    public abstract class CustomWebViewPage : WebViewPage 
    { 
     private List<SystemMessage> _systemMessages = new List<SystemMessage>(); 
     public List<SystemMessage> SystemMessages 
     { 
      get 
      { 
       try 
       { 
        _systemMessages = (List<SystemMessage>())ViewBag.SystemMessages; 
       } 
       catch (Exception) 
       { 
        _systemMessages = new List<SystemMessage>();; 
       } 
       return _systemMessages; 
      } 
     } 
    } 

    public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> where TModel : class 
    { 
     private List<SystemMessage> _systemMessages = new List<SystemMessage>(); 
     public List<SystemMessage> SystemMessages 
     { 
      get 
      { 
       try 
       { 
        _systemMessages = (List<SystemMessage>())ViewBag.SystemMessages; 
       } 
       catch (Exception) 
       { 
        _systemMessages = new List<SystemMessage>();; 
       } 
       return _systemMessages; 
      } 
     } 
    } 
} 

Что это позволяет сделать, это ссылки вы системные сообщения непосредственно в ваших взглядах бритв (обе схемы и регулярные просмотров), как это:

@SystemMessages 

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

<pages pageBaseType="YourProject.Views.CustomWebViewPage"> 

Th необходимо делать во всех файлах web.config, связанных с представлениями, поэтому в папке «Представления» и в любых папках «Области», которые у вас могут быть. После того, как вы установили эту настройку, все ваши представления смогут ссылаться на системные сообщения через синтаксис @SystemMessages.

Более подробную информацию о пользовательских Бритва просмотров вы можете прочитать пост Фила Хаак здесь:

http://haacked.com/archive/2011/02/21/changing-base-type-of-a-razor-view.aspx

+0

Я начал спускаться по этой дороге, но мне не хотелось, чтобы мое управление «сообщениями» получило экземпляр (как часть базового контроллера) для действий, которые совершенно не связаны. Например, у меня есть Html.Action («GetNavMenu») в макете, который отображает соответствующие параметры навигации в этой области с учетом контекста. Но этот вызов будет создавать базовый класс для обработки сообщений тоже? Разве это не совсем пахнет? – DuncanMack

+0

@ DuncanMack Вы говорили, как вы хотите использовать это на странице макета правильно? Поэтому я предлагаю наследовать базовый контроллер только на контроллере/действиях/представлениях, которые используют этот макет, о котором вы говорите. Другой контроллер должен просто наследовать от класса контроллера по умолчанию. Требуется немного планирования и проектирования структуры вашего сайта, но это будет охватывать ваше дело. Кроме того, вы можете добавить логику в свой BaseController, который анализирует текущий маршрут запроса, а затем решает, следует ли ему получать сообщения или нет. – Marko

0

Другой простой вариант (в зависимости, насколько сложно вам это нужно быть) заключается в использовании разделов MVC в:

http://www.c-sharpcorner.com/UploadFile/3d39b4/Asp-Net-mvc-4-layout-and-section-in-razor/

с вашей точки зрения компоновки, вы можете ссылаться на раздел:

@RenderSection("featured", required: false) 

Тогда в любых взглядов, вы можете выбрать то, что происходит внутри этого элемента:

@section featured 
{ 
    <!--Whatever you would like in here--> 
    <h1>@ViewBag.Title.</h1>     
} 

Тогда для любых взглядов, которые не нуждаются в этом, вы просто не включают в себя определение раздела.

Кроме того, если несколько точек зрения использовать те же содержание раздела, вы можете использовать макет ребенка, что только содержание:

  • вашу основную раскладку
  • Определение раздела (так что вы только должны определить его один раз для нескольких просмотров)
Смежные вопросы