An in depth look at ASP.NET MVC’s TempData

Ask around about using TempData in ASP.NET MVC and you’ll get plenty of opinions, but few answers to real questions. “It’s contrary to the MVC pattern,” the more respectful responses will say, others will simply “answer” your question with, “Just don’t use it.” It can be a frustrating wall to encounter when you are simply looking for information to evaluate it as an option for your application or when you need to support code that already uses it.

Few technologies actually deserve that “do not use” label for all situations. The amount of technology elitism that is spread around forums and the internet is staggering. As developers, we have all found small applications for less commonly used technology, even if it is just that sparingly used script or internal web site. There are pros and cons to every technology, and any developer worth their weight in dirt should be able to recognize that.

So, OK, end rant. The point is that despite internet opinion, there are some valid uses for TempData. A wizard based process comes to mind. There are times when you just don’t want to post unused data back to the server every time. It’s a cumbersome process and leaves you responsible for validating what comes back from the client every time, whether you’ve already validated it or not.

What is TempData?

TempData is essentially managed session storage. ASP.NET persists your objects on the session between a single request and then removes them afterward, unless you say otherwise. See the code snippet below for a quick sample:

[HttpPost]
public ActionResult WizardStep1(WizardStep1Model model)
{
     if (ModelState.IsValid)
     {
          TempData["Step1"] = model;
          // OR TempData.Add("Step1", model); works fine as well.
          return RedirectToAction("WizardStep2");
     }

     return View(model);
}

In the WizardStep1 action, we save the model from step 1 to TempData if it is valid, and then we move on to step 2. TempData is essentially a dictionary with a key of string and a value of object, so we can use most of the methods that we would normally use for a Dictionary.

Retreving from and keeping TempData

Let’s consider a three step wizard process. Step 1 is as shown above. We start getting data from the user and move on to Step 2. During Step 2, we gather even more data and move on to step 3 where we (finally!) save everything to the database.

In order to get our data from steps 1 through 3 (cue Brian McKnight), we will need some mechanism to keep the data from step 1 while also adding the data from step 2, since it is only persisted for one request. This is where the Keep method comes in.

[HttpPost]
public ActionResult WizardStep2(WizardStep2Model model)
{
     // We use the same key from when we set the data to get it back...
     WizardStep1Model step1 = (WizardStep1Model)TempData["Step1"];
     // BUT, we can also use ContainsKey or TryGetValue in cases
     // where the data might be null...
     if (step1 == null)
     {
          // The user may have skipped step 1, so we go back.	
          // We could save the step 2 data to TempData if we wanted to.
          return RedirectToAction("WizardStep1");
     }

     // We need to tell TempData to keep the Step 1 model for one more request.<br />	
     TempData.Keep("Step1");
     if (ModelState.IsValid)
     {
          // And, if Step 2 is valid, we'll save it as well.	
          TempData["Step2"] = model;	
          return RedirectToAction("WizardStep3");
     }	

     return View(model);
}

We’ll need to keep the data for Step 1 whether the Step 2 model is valid or not, so we do that outside of the if block for ModelState.IsValid.

It is important to note that TempData only persists for one request. The following GET request following the RedirectToAction qualifies as a request. This means that in the get method for each step, we need to keep the TempData so it is there when we post back. Here is how this would work on the redirect to Step 3.

public ActionResult WizardStep3()
{
     TempData.Keep();
     return View();
}

Notice on the call to TempData.Keep in WizardStep2 that we provided the key that we used to store the Step 1 data to TempData. That marks only that object for retention in TempData, meaning that all others that are not marked will be disposed. In WizardStep3, we have both Step 1 and Step 2’s data in TempData. We can call TempData.Keep with no parameters to mark all objects in TempData for retention.

When we post to WizardStep3, we can retreive both Step 1 and Step 2’s data from TempData, using a similar method to Step 2. There we can save them all to a database at the same time using Entity Framework or any other database persistence.

Why TempData over Session?

You can see from the example above that once the user is finished with the wizard process, that we will no longer need the data from those forms. If you were to save this data to the session, it would stay there until you removed it manually, abandoned the session, or the session expired. Like TempData, the session has its benefits, but in this case it is easier to tell TempData on the off chance that we need to keep the data, rather than to always tell the session to get rid of it.

Conclusion

The truth is that many of the complaints about TempData are valid. It is a loophole outside of the MVC pattern and it is a volatile approach to persisting data. The problem is that despite the views of many opinionated developers, no one pattern is the solution to every problem. If anything else, I hope you have the information to decide whether using TempData is right for you.

Thanks for reading. Feel free to leave any questions or comments.

Advertisements

2 thoughts on “An in depth look at ASP.NET MVC’s TempData

  1. Martijn says:

    Excellent article, personally I see the (over)usage of TempData as a big red-flag in a application. But idd it can have it usage. We use it for getting update messages to the end-user (data saved succesfully, label printer correctly etc) We pick it up automatically in a shared partial view. That way it’s a fire-and-forget system, no matter where the user is directed to by the process, some controller, some action will pick them up and display them once.

    • Ray Kuhnell says:

      I agree with you that it should not be overused, but I think that using it for messages is a great idea. I hadn’t thought of that before. Thanks for the comment!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s