Thursday, March 13, 2008 12:07 AM alerch

Testing TempData, and Mocking SessionState

About a month and a half ago Ben Scheirman wrote about testing TempData in ASP.NET MVC. It's good stuff, and aside from changes between Preview 1 and Preview 2, it still works fine. (See Scott Hanselman's post for some Preview 2-friendly mock helpers using Rhino Mocks.)

While I can easily understand what Ben's code is doing, what I couldn't figure out is why it worked. If you reflect over TempDataDictionary (the type of the Controller.TempData property), you'll see that the data type it persists to the session is an internal structure.

Ben's code, however, mocks out the Session to return the expected TempDataDictionary object. By all counts, that should fail, since the TempDataDictionary won't be getting back the values it expects--it expects the internal map structure.

Well, it turns out I was glossing over one very important fact. TempDataDictionary was written to be smart enough that if the underlying session store either didn't work, or didn't provide the right data, TempData will continue to operate as normal--for the current request only. You can see below that if the session data was null or wasn't the right type, it just creates a new internal map.


(image cut off for space)

One of the benefits of TempData is the cross-request persistence via the session. You might not have known it, but when you call RedirectToAction in your controller action, for example, it's actually resulting in a 300-level HTTP redirect, which means an entirely new HttpContext for the next request. It's basically deferring to the browser to perform the redirect.

So, while Ben's code will definitely work, here's an extension method that can help with mocking out the session a little more "correctly":

public static void NullifySessionState(this HttpSessionStateBase session)
{
    SetupResult.For(session[null]).IgnoreArguments().Return(null);
    session[null] = null;
    LastCall.IgnoreArguments();
}
Filed under: , ,

Comments

# Our daily link (2008-03-13)

Thursday, March 13, 2008 4:19 PM by Trumpi's blog

Sorry about the lack of categories yesterday. I was really lazy. Web ValidatorCalloutExtender does not

# Link Listing - March 13, 2008

Friday, March 14, 2008 9:11 AM by Christopher Steen

ASP.NET Attack and Defense: Securing ASP.NET 2.0 Apps [Via: Keith Brown ] WPF A WPF File Selection...

# re: Testing TempData, and Mocking SessionState

Friday, March 14, 2008 10:02 AM by Paymon

Hi Aaron,

Is there any way to FORCE TempData to work for the "current request" only?

Thanks

# re: Testing TempData, and Mocking SessionState

Friday, March 14, 2008 10:15 AM by alerch

@Paymon

No - but there's no reason to do that. You can either use your own object to store the data, or you could use ViewData - but I'm not sure what you'd be trying to accomplish, exactly?

# re: Testing TempData, and Mocking SessionState

Friday, March 14, 2008 10:56 AM by Paymon

Thanks for your reply Alerch,

What I want to do is:

1. Not create a datatype just as a container for the stuff I want to send to my "View"

2. Want to use typed ViewData (for "one" of the items I'm sending from the controller)

3. Send other pieces of data "too" to be used in my View, without losing the Typed main ViewData (upon which most of my View code is making typed calls)

In fact I have a "Main" view data element, and a few other supplementary items, throughout my architecture.

Any idea?

# re: Testing TempData, and Mocking SessionState

Friday, March 14, 2008 11:05 AM by alerch

Maybe you're looking for something like SmartBag that Jeffrey Palermo came up with:

codebetter.com/.../smartbag-for-asp-net-mvc-take-two.aspx

Leave a Comment

(required) 
(required) 
(optional)
(required)