The following setup kind of works, but it's not the proper use of TempData, and it falls down after the first use. I suspect I'm supposed to be using ViewData, but I'm looking for some guidance to do it correctly.
In my Home controller, I have an Index action that shows which members need to have letters created:
Function Index() As ActionResult
Dim members = GetMembersFromSomeLongRunningQuery()
TempData("members") = members
Return View(members)
End Function
On the Index view, I've got a link to create the letters:
<%=Html.ActionLink("Create Letters", "CreateLetters", "Home")%>
Back in the Home controller, I've got a CreateLetters function to handle this:
Function CreateLetters() As ActionResult
Dim members = TempData("members")
For Each member In members
'[modify member data regarding the letter]
Next
TempData("members") = members
Return RedirectToAction("Letter", "Home")
End Function
Finally, there is a Letter view which creates the actual letters. It's ContentType is "application/msword", so the data actually comes up in Word instead of the browser.
Like I said, this works great the first time through. However, since the letters come up in Word, when the user comes back to the browser, they are still sitting on the screen with the "Create Letters" link. If they try to hit it again (i.e. paper jam after the first attempt), they get an error in CreateLetters because TempData("members") is now empty. I know this is how TempData works (single shot requests), which is why I'm trying to move away from it.
How would this be refactored to use ViewData? Alternatively, how could I simultaneously display the Letter page (i.e. Word document) and redirect the app back to the Index?
I would simply retrieve the object again on the other view but why not cache the object when it is first retrieved
Function Index() As ActionResult
Dim members = GetMembersFromSomeLongRunningQuery()
// Pseudo code (am a C# man sorry)
Cache.Remove("MembersItem")
Cache.Add(members,"MembersItem", CacheExpiry....)
TempData("members") = members
Return View(members)
End Function
Function CreateLetters() As ActionResult
Dim members = Cache.Get("MembersItem")
For Each member In members
'[modify member data regarding the letter]
Next
TempData("members") = members
Return RedirectToAction("Letter", "Home")
End Function
You should also consider caching the results of the query for a specified time or make it dependent on an update. You could also use the session object if it is user specific data.
TempData is designed for keeping data across a redirect and ViewData is designed for passing data to the view. Neither of these are really suitable to what you are trying to achieve although TempData can be made to work in this way by creating an extension method that you can call in the Letter action ( as well as replacing the TempData("members") = members line in CreateLetters )
using System.Web.Mvc;
namespace GoFetchV2.ExtensionMethods
{
public static class TempDataExtensions
{
public static void Keep( this TempDataDictionary tempData, string key )
{
var value = tempData[ key ];
tempData[ key ] = value;
}
}
}
Used like ...
Function CreateLetters() As ActionResult
Dim members = TempData("members")
' Do something with members but want to keep it for the next action '
TempData.Keep("members")
Return RedirectToAction("Letter", "Home")
End Function
Function Letter() As ActionResult
Dim members = TempData("members")
' Do something with members but want to keep it for the next action '
TempData.Keep("members")
' Return the msword binary data '
End Function
Could you just stuff this in an application variable? Application("members")?