articles

Home / DeveloperSection / Articles / Implementing Undo in ASP.NET Webworm’s and MVC

Implementing Undo in ASP.NET Webworm’s and MVC

Implementing Undo in ASP.NET Webworm’s and MVC

Anonymous User 7020 12-Mar-2015

Hi everyone in this article I’m explaining about Undo in ASP.NET MVC.

Description:

There's loads of advice out there recommending that you implement an Undo feature on your website instead of popping up warning messages to protect users from dangerous operations. But there's not a lot of advice out there for how to actually go about doing this in ASP.NET, in either Webworms or MVC. In this course, Keith Brown walks you through his implementation of undo at pluralsight.com to help you get a feel for how you might implement such a feature on your own website.

Using Lambdas for Undo Actions:

In .NET you can use Lambdas to create a function and pass it around like an argument and then that argument can then be invoked at a later time in a different place. That said, with a little careful planning and a few correctly stored Lambdas, you could have a working 'Undo' model in your ASP.NET web sites For this example I'm going to use MVC but this would really work anywhere.

Note: This is a very crude code. More of a proof of concept rather than high-quality, battle-tested code. That said, you probably don't want to use it in your projects as is.

Let’s start:

Open Visual Studio >> File >> New Project >> ASP.NET MVC 4 Web Application

Implementing Undo in ASP.NET Webworm’s and MVC

Give the application name and click ok after click ok popup a window for select project type and click ok

Implementing Undo in ASP.NET Webworm’s and MVC

Now add a Controller its name UndoController

UndoController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace Undo.Controllers
{
    public class UndoController : Controller
    {
        //
        // GET: /Undo/
 
        #region Constants
 
        private const string SESSION_UNDO_ACTION = "Session:UndoAction";
        private const string SESSION_UNDO_MESSAGE = "Session:UndoMessage";
        private const string TEMP_DATA_UNDO_MESSAGE = "UndoResult";
        private const string DEFAULT_UNDO_MESSAGE = "Previous action was undone!";
        private const string DEFAULT_MISSING_UNDO_MESSAGE = "No actions to undo!";
 
        #endregion
 
        #region Undo Action Container (Session)
 
        //contains the current undo action
        private static Action _UndoAction
        {
            get
            {
                return System.Web.HttpContext.Current
                  .Session[SESSION_UNDO_ACTION]as Action;
            }
            set
            {
                System.Web.HttpContext.Current
                  .Session[SESSION_UNDO_ACTION]= value;
            }
        }
 
        //the message to return in the view data for this action
        private static string _UndoMessage
        {
            get
            {
                return System.Web.HttpContext.Current
                  .Session[SESSION_UNDO_MESSAGE] as string;
            }
            set
            {
                System.Web.HttpContext.Current               .Session[SESSION_UNDO_MESSAGE] = value;
            }
        }
 
        #endregion
 
        #region Setting Undo Actions
 
        /// <summary>
        /// Applies an undo action
        /// </summary>
        protected void SetUndo(Action action)
        {
            this.SetUndo(DEFAULT_UNDO_MESSAGE, action);
        }
 
        /// <summary>
        /// Applies an undo action with a return message for the user
        /// </summary>
        protected void SetUndo(string message, Action action)
        {
            UndoController._UndoAction = action;
            UndoController._UndoMessage = message;
        }
 
        /// <summary>
        /// Performs the undo action (if any) and saves the message
        /// </summary>
        protected void PerformUndo()
        {
 
            //check if there is an action
            if (UndoController._UndoAction is Action)
            {
 
                //perform the action and save the message
                Action action = UndoController._UndoAction;
                action();
                this.TempData[TEMP_DATA_UNDO_MESSAGE] =
                  UndoController._UndoMessage;
 
                //and clear out the previous information
                UndoController._UndoAction = null;
                UndoController._UndoMessage = null;
 
            }
            //just save a generic message
            else
            {
                this.TempData[TEMP_DATA_UNDO_MESSAGE] =
                  DEFAULT_MISSING_UNDO_MESSAGE;
            }
 
        }
 
        #endregion
    }
}
 

Basically, we create an abstract Controller that allows us to set an Undo action using a Lambda. You can also set a message for to return to the user that summarizes what the action had done. This example uses a couple of Session variables to hold the parts of the undo action, except I recommend that you create an actual class to house all of the information.

Next, let's look at how we would actually use this controller.

Now add Home Controller.

HomeController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace Undo.Controllers
{
    public class HomeController : UndoController
    {
        #region Constants
 
        private const string SESSION_LIST_CONTAINER = "Session:ListContainer";
 
        #endregion
 
        #region Properties
 
        //a simple list of items for the list
        public static List<string> ListContainer
        {
            get
            {
                List<string> container =System.Web.HttpContext
                  .Current.Session[SESSION_LIST_CONTAINER] as List<string>;
                if (container == null)
                {
                    container = new List<string>();
                    System.Web.HttpContext                     .Current.Session[SESSION_LIST_CONTAINER] = container;
                }
                return container;
            }
        }
 
        #endregion
 
        #region Actions
 
        //shows the list of items
        public ActionResult Index()
        {
            return this.View(HomeController.ListContainer
              .OrderBy(item => item.ToLower()));
        }
 
        //adds an item to the list
        public ActionResult Add(string phrase)
        {
 
            //format the value
            phrase = (phrase ?? string.Empty).Trim();
 
            //add the item if it isn't there yet
            if (!HomeController.ListContainer.Any(item =>
              item.Equals(phrase, StringComparison.OrdinalIgnoreCase)) &&
                !string.IsNullOrEmpty(phrase))
            {
                HomeController.ListContainer.Add(phrase);
            }
 
            //return to the list view
            return this.RedirectToAction("Index");
 
        }
        //removes an item from the list
        public ActionResult Delete(string phrase)
        {
 
            //make sure the item even exists first
            if (HomeController.ListContainer.Any(item =>
              item.Equals(phrase, StringComparison.OrdinalIgnoreCase)))
            {
 
                //since it exists, save the logging message
                this.SetUndo(
                  string.Format("Restored '{0}' to the list!", phrase),
                  () =>
                  {
                      HomeController.ListContainer.Add(phrase);
                  });
 
                //and then actually remove it
                HomeController.ListContainer.Remove(phrase);
 
            }
 
            //return to the main page
            return this.RedirectToAction("Index");
 
        }
        public ActionResult Undo()
        {
 
            //attempts to undo the previous action (if any)
            this.PerformUndo();
 
            //return to the main page
            return this.RedirectToAction("Index");
        }
 
        #endregion
 
    }
}

 This controller allows the user to manage a simple shopping list with an Undo action to allow them to restore a deleted item. It is some ugly code, but you get the idea of how it works.

The important thing you should note is that the Lambda doesn't refer to the instance of the class (this) but instead that the list is a static property. This is important to keep in mind as you develop something like this. When you create the Lambda action, you can't refer to the instance that it was created in. Instead, you need to work with static properties.

Finally, let's look at the ViewPage that is used in this example. 

Index.cshtml:
@using System.Collections.Concurrent;
@{
    ViewBag.Title = "Index";
}
 
 
<html>
  <head>
    <title>Shopping List</title>
  </head>
  <body>
    @{
        IEnumerable<string> list = this.Model as IEnumerable<string>;
     }
 
    <h2>Shopping List</h2>
 
    <p>@this.Html.ActionLink("Undo Previous Action", "Undo")</p>
 
    @if (this.TempData["UndoResult"] is string)
      {
    <p><em>@this.TempData["UndoResult"] as string</em></p>
   }
 
    <hr />
 
    <table>
    @foreach(string item in list) {
      <tr>
        <td>@this.Html.Encode(item) </td>
        <td>@this.Html.ActionLink("Remove", "Delete", new { phrase = item })</td>
      </tr>
    }
    </table>
 
    <hr />
 
    <form action="@this.Url.Action("Add")" method="post" >
      <strong>Add an item:</strong>
      <input type="text" name="phrase" />
      <input type="submit" value="Add" />
    </form>
 
  </body>
</html>

This example is not good looking because we have not to write CSS code but this example is very easy to understand Undo operations in asp.net MVC.

Now our application is ready to use you can run your application.

Output:
1.       When the run application first time no one record in the list

Implementing Undo in ASP.NET Webworm’s and MVC

2.       Add different item in the list 

Implementing Undo in ASP.NET Webworm’s and MVC

3.       Now remove Coconuts item from the list

Implementing Undo in ASP.NET Webworm’s and MVC

4.       Now performs undo operations for Coconuts item

Implementing Undo in ASP.NET Webworm’s and MVC

5.       Now again performs undo operation without removing any items

Implementing Undo in ASP.NET Webworm’s and MVC

Show the message No Action to undo! As for string

Things to Consider:

This code is just a sample of how you could implement and Undo function into your web applications. Here are a few things that you might want to keep in mind before starting something like this.

Make sure that your Undo command doesn't cause you to duplicate code. In this example, the undo command uses a different Add approach than the actual Add action on the controller. This could result in duplicated code or incorrect results.

Determine if you can queue up Undo commands. This example can only do one action at a time, but you could potentially create a Stack of actions that are executed in the reverse order that they were added.

Could you use the same concept to Redo a command after it has been undone?

Be careful with your context - Don't use this inside of your Undo Lambdas.


Updated 01-Jan-2020
I am a content writter !

Leave Comment

Comments

Liked By