Asp.net mvc 4 在MVC4中向布局动态添加内容

Asp.net mvc 4 在MVC4中向布局动态添加内容,asp.net-mvc-4,Asp.net Mvc 4,我有一个主布局文件,所有视图都在其中渲染。我想使用以下规则在此布局的特定区域向用户显示消息: 在我们的维护期内,用户登录后,在每个页面上显示警告 在我们的维护期附近,在用户登录后的每个页面上显示警告(但内容不同于#1) 在正常时间段内,仅在登录时显示消息,而不显示后续页面的消息 我可能希望从其他视图/控制器向该区域附加其他消息,但不想知道是否与维护警告重叠 我真的在努力寻找正确的方法。现在我有一些类似于: public class LayoutController : Controller {

我有一个主布局文件,所有视图都在其中渲染。我想使用以下规则在此布局的特定区域向用户显示消息:

  • 在我们的维护期内,用户登录后,在每个页面上显示警告
  • 在我们的维护期附近,在用户登录后的每个页面上显示警告(但内容不同于#1)
  • 在正常时间段内,仅在登录时显示消息,而不显示后续页面的消息
  • 我可能希望从其他视图/控制器向该区域附加其他消息,但不想知道是否与维护警告重叠
  • 我真的在努力寻找正确的方法。现在我有一些类似于:

    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");
            }
        }
    }
    
    这是正确的思考方式吗?我对使用ViewBag并不感到兴奋,但我看不到更好的管理视图/控制器间共享的方法。对每个视图渲染执行维护时间段检查也感觉不太正确


    我还缺少哪些其他选项?

    为此,我在主布局视图中有一个部分,用于呈现单独的操作。差不多

    (page stuff...)
    <div id="marginMessages>
        Html.Action("GetMarginMessages", "Infrastructure")
    </div>
    (more page stuff...)
    
    (页面内容…)
    
    我认为实现这一点的最佳选择是拥有一个BaseController,您的所有其他控制器都从该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;
        }
    }
    
    现在,您可以通过控制器的messagesService属性访问系统消息。此外,您还可以通过ViewBag.SystemMessages获得这些信息。这样做的原因是,您可以通过创建如下自定义razor视图来进一步推动此操作:

    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声明修改为以下内容:

    <pages pageBaseType="YourProject.Views.CustomWebViewPage">
    
    
    
    这需要在与视图相关的所有web.config文件中完成,以便在您的视图文件夹和您可能拥有的任何区域的视图文件夹中完成。完成此设置后,所有视图都将能够通过@SystemMessages语法引用系统消息

    有关自定义剃须刀视图的更多信息,请阅读Phil Haack的帖子:

    另一个简单的选择(取决于您需要的复杂程度)是使用MVC的部分:

    在布局视图中,可以参照剖面:

    @RenderSection("featured", required: false)
    
    然后,在任何视图中,您都可以选择此元素内部的内容:

    @section featured
    {
        <!--Whatever you would like in here-->
        <h1>@ViewBag.Title.</h1>                 
    }
    
    @栏目特色
    {
    @ViewBag.Title。
    }
    
    然后,对于任何不需要它的视图,您只需要不包含节定义

    此外,如果多个视图使用相同的剖面内容,则可以使用仅包含以下内容的子布局:

    • 参考主布局
    • 定义节(因此您只需定义一次就可以进行多次 (视图)

    是的,但这不意味着你的每一页都会有额外的要求吗?我的意思是,如果布局中有Html.Action helper,那么每次都会有效地触发另一个http请求……没错,但您已经触发了对图像、脚本、局部视图、任何异步部分(如通知)的请求。。。如果只是一条消息中的几句话,那么一个额外的呼叫不太可能产生明显的影响,当你决定以后要在消息中添加更多内容时,将其全部保留在一个或两个位置将有助于保持其可维护性。我认为这是最符合逻辑的,可维护的方法。我开始沿着这条路走下去,但对于完全不相关的操作,让我的“消息”管理被实例化(作为基本控制器的一部分)是不对的。例如,我在布局中有一个Html.Action(“GetNavMenu”),根据上下文呈现该区域中的相关导航选项。但那个调用也会实例化一个基类来处理消息?这闻起来不是很对吗?@DuncanMack你在布局页面上说你想如何使用它,对吗?所以我建议只在使用您所说的布局的控制器/动作/视图上从基本控制器继承。其他控制器应仅从默认控制器类继承。这需要一点规划和设计的结构,你们的网站,但它会涵盖你们的情况。此外,您还可以将逻辑添加到BaseController中,该逻辑分析当前请求路由,然后决定是否应该获取消息。
    <pages pageBaseType="YourProject.Views.CustomWebViewPage">
    
    @RenderSection("featured", required: false)
    
    @section featured
    {
        <!--Whatever you would like in here-->
        <h1>@ViewBag.Title.</h1>                 
    }