Displaying a flash message with ASP.NET MVC

Post-Redirect-Get is a common pattern used in MVC applications. You show a form to the user, they enter their data and click a button to post it to the server. A controller processes the form and returns an HTTP redirect response to the web browser. The browser follows the redirect by getting the given URL.

The form post controller action may need to show a message to the user. For example, saying "your message has been sent". So you have to pass this message to the next page somehow.

The Wrong Way

One approach is to use the controller's TempData dictionary. TempData, by default, uses the session to pass data between requests. The post action method will put the message into TempData. The page we're redirecting to will read TempData and display the message.

Unfortunately using TempData will cause an annoying bug when the browser has already cached the final page. The redirect tells the browser to get the page, but the browser has it cached. So the page is shown without the extra call to the server. This means the TempData is never read.

What's worse is some subsequent page request may not be cached and actually read the TempData which was not intended for it!

A Better Way

Use a cookie to send the message along with the redirect request. The controller action method will look like:

public ActionResult ProcessForm() {
    // ... process form ...
    Response.Cookies.Add(new HttpCookie("FlashMessage", "Data processed") { Path = "/" }));
    return RedirectToAction("Index");
}

In the view we're redirecting to, use JavaScript to read the cookie and display the message. Then delete the cookie so the message is not shown again the next time we load this page.

I use jquery.cookie.js to handle the cookie access. I use a jQuery extension that wraps up the flash message display code:

$.fn.flashMessage = function (options) {
    var target = this;
    options = $.extend({}, options, { timeout: 3000 });
    if (!options.message) {
        options.message = getFlashMessageFromCookie();
        deleteFlashMessageCookie();
    }
    if (options.message) {
        if (typeof options.message === "string") {
            target.html("" + options.message + "");
        } else {
            target.empty().append(options.message);
        }
    }

    if (target.children().length === 0) return;

    target.fadeIn().one("click", function () {
        $(this).fadeOut();
    });

    if (options.timeout > 0) {
        setTimeout(function () { target.fadeOut(); }, options.timeout);
    }

    return this;

    function getFlashMessageFromCookie() {
        return $.cookie("FlashMessage");
    }

    function deleteFlashMessageCookie() {
        $.cookie("FlashMessage", null, { path: '/' });
    }
};

The view contains a div to show the message:

<div id="flash-message"></div>

The flash message extension is called using:

$(function() { $("#flash-message").flashMessage(); });

Would you like access to the sample code repository?

Subscribe to my web development mailing list.

No spam, just occasional web development tips, posts and sample code. Unsubscribe at any time.

Comments
blog comments powered by Disqus