【问题标题】:Success message from Controller to View从 Controller 到 View 的成功消息
【发布时间】:2013-08-20 14:39:13
【问题描述】:

目标

我想在添加某些用户时在我的视图中显示一些消息。

问题

当我们的模型出现问题时,有一种方法 (ModelState.AddModelError) 可以处理不成功的消息。但是,当一切顺利时,我们如何处理给用户的消息说他的操作成功了?

我找到了提供解决方案的this thread,但大约三年过去了,我需要知道:没有其他方法,也许更成熟?不是说这不是,但我们仍然以同样的方式处理成功消息?

【问题讨论】:

  • 要么将其添加到您的模型中,要么使用ViewBag?

标签: c# asp.net asp.net-mvc-4 notifications


【解决方案1】:

Brad Christie'sanswer 扩展,我创建了一个 NuGet 包BootstrapNotifications,它将通过内置的 Bootstrap3 支持为您完成此任务。这个包还支持多种通知类型(错误、警告、成功和信息),带有预先设置的警报,并且易于扩展。

该扩展优雅地支持同一类型和不同类型的每个请求的多个通知。

代码

NotificationExtensions.cs

public static class NotificationExtensions
{
    private static IDictionary<String, String> NotificationKey = new Dictionary<String, String>
    {
        { "Error",      "App.Notifications.Error" }, 
        { "Warning",    "App.Notifications.Warning" },
        { "Success",    "App.Notifications.Success" },
        { "Info",       "App.Notifications.Info" }
    };


    public static void AddNotification(this ControllerBase controller, String message, String notificationType)
    {
        string NotificationKey = getNotificationKeyByType(notificationType);
        ICollection<String> messages = controller.TempData[NotificationKey] as ICollection<String>;

        if (messages == null)
        {
            controller.TempData[NotificationKey] = (messages = new HashSet<String>());
        }

        messages.Add(message);
    }

    public static IEnumerable<String> GetNotifications(this HtmlHelper htmlHelper, String notificationType)
    {
        string NotificationKey = getNotificationKeyByType(notificationType);
        return htmlHelper.ViewContext.Controller.TempData[NotificationKey] as ICollection<String> ?? null;
    }

    private static string getNotificationKeyByType(string notificationType)
    {
        try
        {
            return NotificationKey[notificationType];
        }
        catch (IndexOutOfRangeException e)
        {
            ArgumentException exception = new ArgumentException("Key is invalid", "notificationType", e);
            throw exception;
        }
    }
}

public static class NotificationType
{
    public const string ERROR = "Error";
    public const string WARNING = "Warning";
    public const string SUCCESS = "Success";
    public const string INFO = "Info";

}

_Notifications.cshtml

@using YourApp.Extensions
@{
    var errorList = Html.GetNotifications(NotificationType.ERROR);
    var warningList = Html.GetNotifications(NotificationType.WARNING);
    var successList = Html.GetNotifications(NotificationType.SUCCESS);
    var infoList = Html.GetNotifications(NotificationType.INFO);
}
<!-- display errors -->
@if (errorList != null)
{
    <div class="alert alert-danger alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        @if(errorList.Count() > 1){
            <strong><span class="glyphicon glyphicon-remove"></span> There are @errorList.Count() errors: </strong>
            <ul>
                @foreach (String message in errorList)
                {
                    <li>@Html.Raw(message)</li>
                }
            </ul>
        }
        else{
            <strong><span class="glyphicon glyphicon-remove"></span> Error: </strong>
            @Html.Raw(errorList.First())
        }
    </div>
}

<!-- display warnings -->
@if (warningList != null)
{
    <div class="alert alert-warning alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        @if(warningList.Count() > 1){
            <strong><span class="glyphicon glyphicon-warning-sign"></span> There are @warningList.Count() warnings: </strong>
            <ul>
                @foreach (String message in warningList)
                {
                    <li>@Html.Raw(message)</li>
                }
            </ul>
        }
        else{
            <strong><span class="glyphicon glyphicon-warning-sign"></span> Warning: </strong>
            @Html.Raw(warningList.First())
        }
    </div>
}

<!-- display success -->
@if (successList != null)
{
    <div class="alert alert-success alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        @if(successList.Count() > 1){
            <strong><span class="glyphicon glyphicon-ok"></span> There are @successList.Count() successful notifications: </strong>
            <ul>
                @foreach (String message in successList)
                {
                    <li>@Html.Raw(message)</li>
                }
            </ul>
        }
        else{
            <strong><span class="glyphicon glyphicon-ok"></span> Success! </strong>
            @Html.Raw(successList.First())
        }
    </div>
}

<!-- display success -->
@if (infoList != null)
{
    <div class="alert alert-info alert-dismissable">
        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
        @if(infoList.Count() > 1){
            <strong><span class="glyphicon glyphicon-info-sign"></span> There are @infoList.Count() notifications: </strong>
            <ul>
                @foreach (String message in infoList)
                {
                    <li>@Html.Raw(message)</li>
                }
            </ul>
        }
        else{
            <strong><span class="glyphicon glyphicon-info-sign"></span> </strong>
            @Html.Raw(infoList.First())
        }
    </div>
}

要查看所有这些代码及其使用方式,您可以从 github 下载完整的工作演示。

【讨论】:

    【解决方案2】:

    有几种方法可以给这只猫剥皮。您可以使用 ViewBag:

    ViewBag.SuccessMessage = "<p>Success!</p>";
    

    然后在您的视图中您可以将其渲染到页面:

    @ViewBag.SuccessMessage
    

    我不是 ViewBag 的粉丝,所以我通常会创建一个 ViewModel 对象来保存我的特定视图所需的所有数据。成功的信息就是这样的数据:

    public MyViewModel{
        public bool IsSuccess {get;set;}
    }
    

    然后在你的控制器中,你会将此 ViewModel 传递给你的强类型视图

    [HttpPost]
    public ActionResult Update(MyViewModel vm){
        //Glorious code!
    
       return View(vm)
    }
    

    最后,只要在你的视图中检查它,如果成功就打印一条消息:

    @if(vm.IsSuccess){
         <p>Here is an amazing success message!</p>
    }
    

    另外,您可以使用 TempData 代替它,它的工作方式类似于 ViewBag,但只会持续到您的下一个请求结束,然后被丢弃:

    TempData["SuccessMessage"] = "Success!";
    

    【讨论】:

    • 我认为这种方式并不一致。为什么?好吧,如果没有SuccessMessage,那么我的标记上就会有一个空格。你能告诉我另一种“剥猫皮”的方法吗?呵呵:P
    • 不会有空格,因为@ViewBag.SuccessMessage 是一个空字符串,所以页面不会呈现任何内容。
    • 哦,好的。现在你的答案好多了。谢谢,@克里斯!为Glorious code!点赞,哈哈!
    • 酷,如果这对您有帮助,请随时标记为答案:)
    • 我相信这是另一个问题。考虑以下。我们需要实现一个行为,例如从用户添加视图提交数据和成功的 db 请求,我们希望重定向到列表页面。这种情况下我们需要处理更多的代码
    【解决方案3】:

    TempData 是一种将一次性交给 UI 以通知用户的好方法。关于它们的重要部分是它们在动作调用之间持续存在,但一旦被读取就会被删除。因此,如果只是传递“它有效”的信息,它就很有效。

    您可以通过多种方式将它们联系起来,但我会举一个一般性的例子来帮助您:

    public static class NotificationExtensions
    {
        private const String NotificationsKey = "MyApp.Notifications";
    
        public static void AddNotification(this ControllerBase controller, String message)
        {
            ICollection<String> messages = controller.TempData[NotificationsKey] as ICollection<String>;
            if (messages == null)
            {
                controller.TempData[NotificationsKey] = (messages = new HashSet<String>());
            }
            messages.Add(message);
        }
    
        public static IEnumerable<String> GetNotifications(this HtmlHelper htmlHelper)
        {
            return htmlHelper.ViewContext.Controller.TempData[NotificationsKey] as ICollection<String> ?? new HashSet<String>();
        }
    }
    

    现在在您的操作中,您可以调用 this.AddNotification("User successfully added!"); 并在您的视图中显示它们:

    @foreach (String notification in Html.GetNotifications())
    {
        <div class="notification">
            <p>@notification/p>
            <i class="icon-close"></i>
        </div>
    }
    

    (...或类似的东西) 可以有效地放置在您的主视图中,并用作执行任何操作的一般通知方法。 (类似于 StackOverflow 在某些事件期间在页面顶部显示金条的方式)。

    【讨论】:

    • 这是一个非常优雅的解决方案。我一直在寻找如何正确地做到这一点。 +1
    【解决方案4】:

    TempData 集合是一个很好的解决方案。它的值在请求结束时被清除,这使其成为一次性消息的理想选择,例如通知用户某事成功。

    控制器

    TempData["Message"] = "Operation successful!";
    

    查看

    @TempData["Message"]
    

    是的,这仍然是目前最好的方法。

    【讨论】:

      【解决方案5】:
      TempData
      

      使用 MVC TempData - TempData

      它仅适用于该页面请求。非常适合发送成功消息等。

      【讨论】:

      • 不推荐使用Tempdata
      【解决方案6】:

      从概念上讲,我认为答案仍然成立。如果消息是视图的组成部分,它应该是ViewModel 的一部分。 TempData 是在不修改 ViewModel 定义的情况下传递数据的快捷方式,有些人对此表示不满。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多