3

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

  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 并不感到兴奋,但我没有看到更好的方法来管理视图间/控制器共享。并且对每个视图渲染进行维护时间段检查也感觉不太正确。

我还缺少哪些其他选择?

4

3 回答 3

4

为此,我将在主布局视图中有一个部分,用于呈现单独的操作。就像是

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

作为控制器,您可以InfrastructureController在其中处理诸如边际消息、通知消息等横切关注点。该控制器将有一个方法GetMarginMessages来确定是否需要显示任何消息,如果需要,则返回包含这些消息的局部视图,但您希望它们呈现。如果没有消息,它可以返回EmptyResult,你应该确保你的页面在div空时看起来没问题。

对于更复杂的逻辑,您可以创建一个派生自该操作过滤器的操作过滤器,该过滤器可以在控制器方法 ( ) 之后或视图呈现 () 之前ActionFilterAttribute捕获请求。(理论上,你使用哪一个并不重要。)OnActionExecuted()OnResultExecuting()

从那里,您可以使用filterContextto:

  • 查看用户刚刚点击了哪个控制器方法和操作
  • 查看控制器将什么值放入模型中ViewBag,以及TempData
  • 添加/删除/更改模型中的值ViewBag, 和TempData

所以从那里,你应该能够设置值来告诉你的消息渲染部分视图它需要做什么。然后,局部视图可以检索这些值并根据需要使用它们(只需记住在尝试使用它们之前对所有内容进行空检查)。

设置后,此操作过滤器可应用于:

  • 所有方法,通过将其添加到GlobalFilterCollection方法Application_Start() 中的Global.asax.cs
  • 整个控制器,通过将其添加public class MyController : Controller到控制器文件中的行上方
  • 特定方法,通过在该方法上方添加它

当然,在这些地方的任何一个地方,您都可以将值传递给构造函数,并在过滤器中有一些逻辑来计算出哪个覆盖了哪个。

于 2013-08-08T16:18:28.837 回答
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 声明修改为以下内容:

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

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

有关自定义 Razor 视图的更多信息,您可以在此处阅读 Phil Haack 的帖子:

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

于 2013-08-09T14:25:30.287 回答
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>                 
}

然后对于不需要它的任何视图,您只需不包含部分定义。

此外,如果多个视图使用相同的部分内容,则可以使用仅内容为的子布局:

  • 参考您的主要布局
  • 定义部分(因此您只需为多个视图定义一次)
于 2015-04-20T20:35:17.733 回答