开发者

Flash equivalent in ASP.NET MVC 3

There is a feature called 'flash' in ruby on rails where you can put a message in 'flash', redirect, and th开发者_JS百科e message is available in the next action.

Example of the use of flash:

There is a controller action Account.ChangePassword. If password change is successful, ChangePassword will fill flash with a message 'Password change successful', and then redirects to Account.Profile. In Account.Profile, the message is available so it can be displayed in the profile page.

Is there something equivalent in ASP.NET MVC 3?

I know I can build this feature myself using tempdata, but does MVC 3 have something built in?


Endy,

I 'borrowed' this from the tekpub series:

namespace System.Web.Mvc {
    public static class FlashHelpers {

        public static void FlashInfo(this Controller controller,string message) {
            controller.TempData["info"] = message;
        }
        public static void FlashWarning(this Controller controller, string message) {
            controller.TempData["warning"] = message;
        }
        public static void FlashError(this Controller controller, string message) {
            controller.TempData["error"] = message;
        }

        public static string Flash(this HtmlHelper helper) {

            var message = "";
            var className = "";
            if (helper.ViewContext.TempData["info"] != null) {
                message =helper.ViewContext.TempData["info"].ToString();
                className = "info";
            } else if (helper.ViewContext.TempData["warning"] != null) {
                message = helper.ViewContext.TempData["warning"].ToString();
                className = "warning";
            } else if (helper.ViewContext.TempData["error"] != null) {
                message = helper.ViewContext.TempData["error"].ToString();
                className = "error";
            }
            var sb = new StringBuilder();
            if (!String.IsNullOrEmpty(message)) {
                sb.AppendLine("<script>");
                sb.AppendLine("$(document).ready(function() {");
                //sb.AppendFormat("$('#flash').html('{0}');", message);
                sb.AppendFormat("$('#flash').html('{0}');", HttpUtility.HtmlEncode(message));
                sb.AppendFormat("$('#flash').toggleClass('{0}');", className);
                sb.AppendLine("$('#flash').slideDown('slow');");
                sb.AppendLine("$('#flash').click(function(){$('#flash').toggle('highlight')});");
                sb.AppendLine("});");
                sb.AppendLine("</script>");
            }
            return sb.ToString();
        }

    }
}

typical usage (inside controller):

public ActionResult Delete(int id, FormCollection collection)
{
    var item = _session.Single<UserActions>(x=>x.ID == id);
    try
    {
        _session.Delete<UserActions>(item);
        _session.CommitChanges();
        this.FlashInfo("UserAction deleted ...");
        return RedirectToAction("Index");
    }
    catch
    {
        this.FlashError("There was an error deleting this record");
        return View("Edit",item);
    }
}

the css is pretty straightfwd too:

.info
{
    background-color: #CCFFCC;
    border-top: 1px solid #FFCC66;
    border-bottom: 4px solid #FFCC66;
    padding: 6px;
    font-family: helvetica;
    font-size: 1.1em;
    text-align: center;
    border-top-color: #006600;
    border-bottom-color: #006600;
    font-weight: bold;
    color: #339933;
    cursor:pointer;
}
.warning
{
    background-color: #FFFF99;
    border-top: 1px solid #FFCC66;
    border-bottom: 4px solid #FFCC66;
    padding: 6px;
    font-family: helvetica;
    font-size: 0.9em;
    text-align: center;
    border-top-color: #CC9900;
    border-bottom-color: #CC9900;
    font-weight: bold;
    color: #663300;
    cursor:pointer;
}
.error
{
    background-color: #FFCC99;
    border-top: 1px solid #FFCC66;
    border-bottom: 4px solid #FFCC66;
    padding: 4px;
    font-family: helvetica;
    font-size: 1.1em;
    text-align: center;
    border-top-color: #800000;
    border-bottom-color: #800000;
    font-weight: bold;
    color: #990000;
    cursor:pointer;
}

and in your site.master

<%=Html.Flash() %>
<body>
    <div id="flash" style="display: none">
    </div>
.... etc
</body>

enjoy...


No, the TempData solution is what you are looking for.


I want to upgrade Jim's answer to use MVC 3's new helper functions.

Helper functions make it easy to write functions that primarily return Html/javascript so you don't have to use string builder or string concatenation. It results in much cleaner code.

FlashHelpers.cs :

namespace System.Web.Mvc {

    public static class FlashHelpers {

        public static void FlashInfo(this Controller controller,string message) {
            controller.TempData["info"] = message;
        }
        public static void FlashWarning(this Controller controller, string message) {
            controller.TempData["warning"] = message;
        }
        public static void FlashError(this Controller controller, string message) {
            controller.TempData["error"] = message;
        }
    }
}

Then you create the ASP.NET App_Code folder and create a .cshtml file there (Flash.cshtml probably) and paste in the following code

App_Code/Flash.cshtml :

@helper FlashMessage(TempDataDictionary tempData){
    var message = "";
    var className = "";
    if (tempData["info"] != null)
    {
        message = tempData["info"].ToString();
        className = "flashInfo";
    }
    else if (tempData["warning"] != null)
    {
        message = tempData["warning"].ToString();
        className = "flashWarning";
    }
    else if (tempData["error"] != null)
    {
        message = tempData["error"].ToString();
        className = "flashError";
    }
    if (!String.IsNullOrEmpty(message))
    {
        <script type="text/javascript">
            $(document).ready(function() {
            $('#flash').html('@message');
            $('#flash').toggleClass('@className');
            $('#flash').slideDown('slow');
            $('#flash').click(function(){$('#flash').toggle('highlight')});
            });
        </script>
    }
}

This is doing what the Flash function was doing before but in a much cleaner way.

Rest of the things stay the same as in Jim's answer except the way you call it. Instead of using @Html.Flash(), you need to call it like so:

@Flash.FlashMessage(TempData)

Please note that Flash in the above line is the name of the .cshtml file in the App_Code folder.

Hope it helps.


I refactored Imran's answer to make the code shorter:

Helpers/FlashHelper.cs

namespace System.Web.Mvc
{
    public enum FlashEnum
    {
        Success = 1,
        Info = 2,
        Warning = 3,
        Error = 4
    }
    public static class FlashHelper
    {
        public static void Flash(this Controller controller, string message, 
            FlashEnum type = FlashEnum.Success)
        {
            controller.TempData[string.Format("flash-{0}", 
                type.ToString().ToLower())] = message;
        }
    }
}

App_Code/Flash.cshtml

@helper FlashMessage(System.Web.Mvc.TempDataDictionary tempData)
{
    var flash = tempData.Where(item => item.Key.StartsWith("flash-"))
        .Select(item => 
            new { Message = item.Value, ClassName = item.Key }).FirstOrDefault();
    if (flash != null)
    {
    <script type="text/javascript">
        $(function () {
            var $flash = $('<div id="flash" style="display:none;">');
            $flash.html('@flash.Message');
            $flash.toggleClass('flash');
            $flash.toggleClass('@flash.ClassName');
            $('body').prepend($flash);
            $flash.slideDown('slow');
            $flash.click(function () { $(this).slideToggle('highlight'); });
        });
    </script>
    }
}

CSS code borrowed from twitter bootstrap

/* Styles for flash messages
-----------------------------------------------------------*/

.flash
{
    padding: 8px 35px 8px 14px;
    margin-bottom: 18px;
    border: 1px solid;
}

.flash-success
{
    color: #468847;
    background-color: #DFF0D8;
    border-color: #D6E9C6;
}

.flash-info
{
    color: #3A87AD;
    background-color: #D9EDF7;
    border-color: #BCE8F1;
}

.flash-warning
{
    color: #C09853;
    background-color: #FCF8E3;
    border-color: #FBEED5;
}

.flash-error
{
    color: #B94A48;
    background-color: #F2DEDE;
    border-color: #EED3D7;
}

usage inside controller:

this.Flash("Huston, we have an error!!", FlashEnum.Error);

usage inside layout (or other cshtml file):

@Flash.FlashMessage(TempData)


I know there are several solutions out there, but I was looking for a pure C# solution. I like @TylerLong's solution the best, though I wanted to support multiple messages for each type. Plus, this is updated for ASP.NET MVC4, and being that there are no config file changes necessary, it would probably work for other versions of the MVC framework as well.

Features

  • Pure C# solution
  • Uses view helpers, partials and an extension method to the Controller class
  • Should be compatible with multiple versions of the MVC framework
  • Supports multiple messages per type
  • No config changes to your Web.config files

1) Create MvcProject/Helpers/FlashHelper.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcProject.Helpers
{
    public enum FlashLevel
    {
        Info = 1,
        Success = 2,
        Warning = 3,
        Danger = 4
    }

    public static class FlashHelper
    {
        public static void Flash(this Controller controller, string message, FlashLevel level)
        {
            IList<string> messages = null;
            string key = String.Format("flash-{0}", level.ToString().ToLower());

            messages = (controller.TempData.ContainsKey(key))
                ? (IList<string>)controller.TempData[key]
                : new List<string>();

            messages.Add(message);

            controller.TempData[key] = messages;
        }
    }
}

2) Create MvcProject/Views/Shared/_Flash.cshtml as a Partial:

@helper FlashMessage(System.Web.Mvc.TempDataDictionary tempData)
{
    <div class="flash-messages">
    @foreach (FlashLevel level in (FlashLevel[]) Enum.GetValues(typeof(FlashLevel)))
    {
        string type = level.ToString().ToLower();
        string key = "flash-" + type;

        if (tempData.ContainsKey(key))
        {
            IList<string> messages = (IList<string>)tempData[key];

            foreach (string message in messages)
            {
                <p class="alert alert-@type" role="alert">@message</p>
            }
        }
    }
    </div>
}

@FlashMessage(TempData)

3) Render the _Flash partial in MvcProject/Views/Shared/_Layout.cshtml

@Html.Partial("_Flash")

This will cause the flash messages to be included in the web page.

4) Add flash messages in your Controllers

The last piece of the puzzle is in your Controllers, which should now have a method called Flash(string message, FlashLevel level):

using MvcProject.Helpers;

public class FoosController : Controller
{
    public ActionResult Edit(int id, FooViewModel model)
    {
        // ...
        this.Flash("Foo was updated", FlashLevel.Success);
        this.Flash("Another success message!", FlashLevel.Success);
        this.Flash("But there was a slight problem...", FlashLevel.Warning);

        return RedirectToAction("Edit", new { id = id });
    }
}


I've written an example of Rails style Flash messages for ASP.NET using cookies and JavaScript on the client, with source code & example.

  • Rails-style "flash" messages for ASP.NET MVC with Razor view templates
  • Source code (gist.github.com)

Usage

Add a reference to the two JavaScript files: jquery.cookie.js (standard jQuery cookie plugin) and jQuery.flashMessage.js

Reference the _Flash.cshtml partial within your main layout view. This will determine where the flash messages appear.

@Html.Partial("_Flash")

Add the FlashMessageExtensions.cs static extension method class to your website.

Within your MVC controllers simply use the .Success("message to show") and the corresponding Error, Warning or Information extension methods on ActionResult to set the flash cookie on the response. Remember to add the necessary using statement to use these methods from flash extension class above.

[HttpPost]
public ActionResult Create()
{
    return RedirectToAction("Index").Success("Message shown to user after redirect");
}

By default the flash message will fade out after 3 seconds or if the user clicks on it. The fade-out delay is configurable by setting the timeout option when configuring the JavaScript flash plugin, or can be disabled be setting it to 0.


This is a much requested feature which was in MvcContrib 2.0 - I am not sure if it made it to 3.0. I personally keep it in the session for a short period when I am doing PRG = Post-Redirect-Get.


I think this would make you happy. https://github.com/khalidabuhakmeh/MvcFlash

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜