I am using ASP.NET MVC 3 to build a web application.
What I am trying to do is pass values between two controllers, though there are many ways to do this I am particular interested in using TempData for this.
public ActionResult Action1()
{
string someMessage;
Test obj = SomeOperation();
if(obj.Valid)
{
someMessage = obj.UserName;
}
else
{
someMessage = obj.ModeratorName;
}
TempData["message"] = someMessage;
return RedirectToAction("Index");
}
public ActionResult Index()
{
ViewBag.Message = TempData["message"]
return View();
}
So is the use of TempData here correct ? I mean under best programming practices is this correct way of using TempData ?
In what real time cases should TempData be used ?
Note : I have gone through the following links
When to use TempData vs Session in ASP.Net MVC
http://www.gregshackles.com/2010/07/asp-net-mvc-do-you-know-where-your-tempdata-is/
Thanks
TempData is a bucket where you can dump data that is only needed for the following request. That is, anything you put into TempData is discarded after the next request completes. This is useful for one-time messages, such as form validation errors. The important thing to take note of here is that this applies to the next request in the session, so that request can potentially happen in a different browser window or tab.
To answer your specific question: there's no right way to use it. It's all up to usability and convenience. If it works, makes sense and others are understanding it relatively easy, it's good. In your particular case, the passing of a parameter this way is fine, but it's strange that you need to do that (code smell?). I'd rather keep a value like this in resources (if it's a resource) or in the database (if it's a persistent value). From your usage, it seems like a resource, since you're using it for the page title.
Hope this helps.
Please note that MVC 3 onwards the persistence behavior of TempData has changed, now the value in TempData is persisted until it is read, and not just for the next request.
The value of TempData persists until it is read or until the session
times out. Persisting TempData in this way enables scenarios such as
redirection, because the values in TempData are available beyond a
single request.
https://msdn.microsoft.com/en-in/library/dd394711%28v=vs.100%29.aspx
Just be aware of TempData persistence, it's a bit tricky. For example if you even simply read TempData inside the current request, it would be removed and consequently you don't have it for the next request. Instead, you can use Peek method. I would recommend reading this cool article:
MVC Tempdata , Peek and Keep confusion
Related
I have 3 partialviews with 3 viewmodels on page:
List of accounts
Modal popup (you can modify multiple accounts here)
Search panel
I want to refresh 1. after doing POST on 2. This is straightforward, but what if I want to keep results I got after using Search Panel?
I can do this in 2 ways but both seems bad (correct me if I am wrong).
First (the one I chose and works) is to store viewmodel used in 3. in TempData. I do Search (POST) and save passed viewmodel in TempData. Then whenever I do POST on different partialview I can refresh 1. using data(search parametrs) from TempData.
private const string SearchDataKey = "SearchData";
[HttpGet]
public PartialViewResult RefreshData()
{
if (TempData[SearchDataKey] != null)
return PartialView("AccountListView", PrepareAccountListViewModelForSearchData(TempData[SearchDataKey] as AccountSearchViewModel));
else
return PartialView("AccountListView", PrepareAccountListViewModel());
}
and saving ViewModel:
public PartialViewResult Search(AccountSearchViewModel searchParameters)
{
...
TempData[SearchDataKey] = searchParameters;
return PartialView("AccountListView", databaseAccountListViewModel);}
Second approach is to always POST "big" viewmodel with all 3 viewmodels. This way I will have data from Search's viewmodel but I will send many not needed information instead just Modal Popup's viewmodel which I need to call procedure.
I asked few MVC folks with better experience and they said they never had to store viewmodel in TempData but it still seems more reasonable than having 1 Big form and passing everything in every POST.
Do you know any better ways to handle this or which one is correct?
PS. Topic had "Best Practice" but was removed cause of warning message. I hope asking about opinion is still allowed on SO.
PS2. Most of my POSTs & GETs after initial load are through Ajax.
I do Search (POST)
This seems semantically incorrect to me. Searching is an action that shouldn't modify any state on the server. So using GET seems more appropriate. And when you use GET you have the benefit that all parameters are already present in the query string and thus preserved upon successive POST actions (like modifying an account in your case). So your RefreshData action could take the AccountSearchViewModel as parameter and the model binder will take care of the rest.
I want to pass a class object from one controller action to different controller's action.
Sender Action
public class CourseController : Controller
{
[HttpPost]
public ActionResult CreateNewCourse(CourseViewModelBase courseViewModel)
{
if (ModelState.IsValid)
{
// Do some stuff
return RedirectToAction("CreateNewProject", "Project",
new { courseVM = courseViewModel});
}
// Bad happened
return View("CreateNewCourse", courseViewModel);
}
Receiver Action
public class ProjectController : Controller
{
[HttpGet]
public ActionResult CreateNewProject(CourseViewModelBase courseVM)
{
// Use CourseVM data and do other stuff
return View("Create", projectCreateViewModel);
}
}
I am getting data properly in Sender Action and Receiver Action is called properly from the redirect to action call. However courseVM in Receiver Action is null.
I know this is a very old question and had been asked repetitively. But I found that most of the answers suggested to use TempData and were answered in 2008/2009. I believe there would be someway to pass data using RedirectToAction without using TempData. If there is not then I would go with TempData only.
Finding
If I pass some simple data e.g. new {id = courseViewModel.CourseDuration} and change the argument in Receiver action to id then id is properly received.
Similar Questions
Question 1
Question 2
Question 3
Question 4
Question 5
Question 6, tried to use this one but did not workout
Question 7
Question 8
Question 9
Question 10
Most of the answers in above questions are dated back in 2008/09 and uses tempdata.
This question itself is now about a year old, but I came across it so I thought I would help out others who come across it in the future. The accepted answer doesn't work - the complex object still arrives at the receiving action null.
I found that this answer from 2012 is still valid. You just can't pass complex objects in an HttpGet request (by nature this is what a RedirectToAction is - again, not something you can change). You can only pass scalar values: int, string, etc.
Make sure you've ruled out the below two options:
Avoid sending a complex object altogether, and send only scalar values. Obviously this is only an option sometimes - but I mention it as a reminder to consider it.
Skip the receiving Get action altogether - perform its logic & return the View directly from your Post action. Ie; return View("ReceivingViewName", viewmodel) Again, will only work for some situations, more than likely you'll need the other action and thus will need the Redirect, but worth remembering as a possiblity.
If you can't get around the problem, and have eliminated the two above options, your options are:
Persist the data to Database, possibly using a temp table if you know the data won't be used later. Send the primary key to the receiving action, and once there, query the database. This is the "cleanest" option.
[Edited Option] Store the object in TempData (data lasts only thru the next request in which it is used - if it's not used, it will hang around for the life of session) or Session (data lasts for life of session). Neither are really great options. TempData is probably the better of the two, as its lifespan is potentially shorter... but you'll still have to consider what happens when a page reload occurs or a subsequent request is made to the method (WebGrid paging, for example - which was my scenario). For these specific scenarios, I originally recommended getting the data out of TempData, and then putting it back in so it's available for a subsequent request to that action. Since TempData actually hangs around until it's used once, that makes this option even less desirable, since it won't go away if the user navigates elsewhere. More info on this in the answers here. Bottom line is don't put anything in TempData unless you intend to use it right away. If you don't need the data for a specific scenario like paging, and you put it in TempData and immediately consume it in the receiving method, without putting it back in, this option is okay. The first option is still better.
use this
return RedirectToAction("ActionName", "ControllerName", modelObj);
in your case
return RedirectToAction("CreateNewProject", "Course", courseViewModel);
You can also use
TempData
i am teaching myself MVC and am struggling to work out the best solution to my problem. I have a search controller with a large amount of input fields. I will also have multiple overloads of the search fields eg basic search advanced search searchByCategory etc.
When the search form is posted i redirect to another action that displays the search results. If i press f5 the get action is fired again as opposed to the search results being refreshed in the action that my post redirects to. Ideally i would like to redirect to a search results Action Method without using the query string, or detect when refresh is hit and requery the database and just use different actions within the same search controller. I have read a lot of posts about this and the only 2 solutions i can find is using a session variable or TempData.Can anybody advise as to what is the best practice
From the Comments
Most of the time I prefer to use TempData in place of QueryString. This keeps the Url clean.
Question
Can anybody advise as to what is the best practice
Answer
Once the data is sent to Action Method to get the results from Database after then As per my knowledge you can use TempData to store the posted data. It is like a DataReader Class, once read, Data will be lost. So that stored data in TempData will become null.
var Value = TempData["keyName"] //Once read, data will be lost
So to persist the data even after the data is read you can Alive it like below
var Value = TempData["keyName"];
TempData.Keep(); //Data will not be lost for all Keys
TempData.Keep("keyName"); //Data will not be lost for this Key
TempData works in new Tabs/Windows also, like Session variable does.
You could use Session Variable also, Only major problem is that Session Variable are very heavy comparing with TempData. Finally you are able to keep the data across Controllers/Area also.
Hope this post will help you alot.
I think there is no need to even call Get Method after performing search although its good habit in case of if your are performing any add/update/delete operation in database. But in your case you can just return the View from your post method and no need to store data in tempdata or session until you really don't need them again. So do something like this:
[HttpPost]
public virtual ActionResult PerformSearch(SearchModel model)
{
// Your code to perform search
return View(model);
}
Hope this will help.
Hi thanks
I have had a chance to revisit this. the problem was i neglected to mention that i am using jQuery mobile which uses Ajax by default even for a normal Html.BeginForm. I was also returning a view which i have since learned will not updated the URL but only render new html for the current controller. my solution is to set the action, controller and html attributes in the Html.Beginformas follows :
#Html.BeginForm("Index", "SearchResults", FormMethod.Post, new { data_ajax = "false" })
inside the parameters for the index action of the searchResults controller I have a viewModel that represents the fieldset of the form that i am posting. The data-ajax="false" disables the Ajax on the form post and MVC takes care of matching the form post parameters to my model. This allows the url to update and when i press f5 to refresh the controller re-queries the database and updates the search results.
Thanks everybody for your help. I was aware of TempData but it is good to know that this is preferred over session data so i voted up your answer
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateUser([Bind(Exclude = "Id")] User user)
{
...
db.SubmitChanges();
ViewData["info"] = "The account has been created.";
return RedirectToAction("Index", "Admin");
}
This doesnt keep the "info" text in the viewdata after the redirectToAction.
How would I get around this issue in the most elegant way?
My current idea is to put the stuff from the Index controlleraction in a [NonAction] and call that method from both the Index action and in the CreateUser action, but I have a feeling there must be a better way.
Thanks.
You can use TempData.
TempData["info"] = "The account has been created.".
TempData exists exactly for this situation. It uses Session as storage, but it will not be around after the second response.
From MSDN:
A typical use for a TempDataDictionary object is to pass data from an action method when it redirects to another action method. For example, an action method might store information about an error in the controller's TempData property (which returns a TempDataDictionary object) before it calls the RedirectToAction method. The next action method can then handle the error and render a view that displays an error message.
Use ViewData if your data should be accessible in View during "this" request. Use `TempData' if your data is for "next" request (for example POST-REDIRECT-GET design pattern).
If you need this more than once, a nice workaround would be creating ActionFilterAttributes which export/import the tempdata to viewdata and vice-versa. You can pass your ModelState in this way very nicely as well (demonstrated here - #13).
With a few adjustments to that piece of code you would have a clean solution, I think.
You could use the TempData controller property, but it has the disadvantage that it uses the session storage in the background. This means that you'll have extra work getting it to function on a web farm and you'll need to have sessions enabled in your application in the first place.
An alternative is to use cookies if you only need to transport a short message. This does require proper encryption of the cookie. Not relying on the TempData property also allows you to set messages in a non MVC context, for example in a classic ASHX page.
Take a look at FlashMessage which can save you some work implementing this yourself.
Since TempData appears to use storage, and any form of ITempDataProvider that is not "in-process", requires the object to be Serializable, TempData seems woefully inadequate in web farm situations... (ViewDataDictionary isn't itself serializable...) Does anyone have any suggestions for this?
The answer is TempData. The usage difference for clarification is as the following:
TempData = passing data from Action to another Action
ViewData = passing data from Action to a View
I am trying to get the hang of MVC framework so bear with me.
Right now, the only thing I'm using the session store for is storing the current logged in user. My website is simple. For this example, consider three domain objects, Person, Meeting, and File. Users can log in and view a "members only" profile of a meeting and can add files to it, or view a meeting's public "profile" if they aren't logged in.
So, from the meeting's private profile, with a logged in user, I have a "add files" link. This link routes to FileContoller.Add(int meetingId). From this action, I get the meeting the user want to add files to using the meeting id, but after the form is posted, I still need to know which meeting the user is adding files to. That's where my question lies, should I pass the "currently interacting with" meeting through TempData, or add it to the Session store?
This is how I currently have the Add action setup, but it's not working:
public ActionResult Add(int meetingId)
{
try
{
var meeting = _meetingsRepository.GetById(meetingId);
ViewData.Model = meeting;
TempData[TempDataKeys.CurrentMeeting] = meeting; /* add to tempdata here */
}
catch (Exception)
{
TempData[TempDataKeys.ErrorMessage] = "Unable to add files to this meeting.";
return RedirectToRoute("MeetingsIndex");
}
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(FormCollection form)
{
var member = Session[SessionStateKeys.Member] as Member;
var meeting = TempData[TempDataKeys.CurrentMeeting] as Meeting; /* meeting ends up null here */
if (member == null)
{
TempData[TempDataKeys.ErrorMessage] = "You must be logged in to add files to an meeting.";
return RedirectToRoute("LoginPage");
}
if (meeting == null)
{
TempData[TempDataKeys.ErrorMessage] = "An error occurred. No meeting selected.";
return RedirectToRoute("MeetingsIndex");
}
// add files to meeting
TempData[TempDataKeys.Notification] = "Successfully added.";
return RedirectToRoute("AddFiles", new {meetingId = meeting.MeetingId});
}
Edit:
Based on most of the answers, can any one provide any examples on what kind of data (other than messages) should be stored in TempData vs Session?
TempData is session, so they're not entirely different. However, the distinction is easy to understand, because TempData is for redirects, and redirects only. So when you set some message in TempData and then redirect, you are using TempData correctly.
However, using Session for any kind of security is extremely dangerous. Session and Membership are entirely separate in ASP.NET. You can "steal" sessions from other users, and yes, people do attack web sites this way. So if you want to selectively stop a post information based on whether a user is logged in, look at IsAuthenticated, and if you want to selectively show information based on what type of user is logged in, you use a Role provider. Because GETs can be cached, the only way to selectively allow access to an action in a GET is with AuthorizeAttribute.
Update In response to your edited question: You already have a good example of using TempData in your question, namely, returning a simple error message after a failed POST. In terms of what should be stored in Session (beyond "not much"), I just think of Session as a user-specific cache. Like the non-user-specific Cache, you should not put security-sensitive information there. But it's a good place to stick stuff which is relatively expensive to look up. For example, our Site.Master has the user's full name displayed on it. That is stored in a database, and we don't want to do a database query for it for every page we serve. (An installation of our application is used in a single company, so a user's full name is not considered "security-sensitive.") So if you think of Session as a cache which varies by a cookie which the user has, you won't be far wrong.
The default TempData provider uses the session so there really isn't much of a distinction, except that your TempData is cleared out at the end of the next request. You should use TempData when the data needs only to persist between two requests, preferably the second one being a redirect to avoid issues with other requests from the user -- from AJAX, for example -- deleting the data accidentally. If the data needs to persist longer than that, you should either repopulate the TempData or use the Session directly.
You can use it as per your requirement. A clarification can be,
TempData Vs Session
TempData
TempData allow us to persisting data for the duration of single subsequent request.
ASP.net MVC will automatically expire the value of tempdata once consecutive request returned the result (it means, it alive only till the target view is fully loaded).
It valid for only current and subsequent request only
TempData has Keep method to retention the value of TempData.
Example:
TempData.Keep(), TempData.Keep(“EmpName”)
TempData internally stored the value in to Session variable.
It is used to stored only one time messages like validation messages, error messages etc.
Session:
Session is able to store data much more long time, until user session is not expire.
Session will be expire after the session time out occurred.
It valid for all requests.
N/A
Session varible are stored in SessionStateItemCollection object (Which is exposed through the HttpContext.Session property of page).
It is used to stored long life data like user id, role id etc. which required throughout user session.
TempData and session, both required typecasting for getting data and check for null values to avoid run time exception.
"It doesn't work" isn't very descriptive, but let me offer a couple suggestions.
Under the hood, TempData uses Session to store values. So there isn't much difference in terms of storage mechanisms or anything like that. However, TempData only lasts until the next request is received.
If the user makes an ajax request in between form posts, TempData is gone. Any request whatsoever will clear TempData. So it's really only reliable when you're doing a manual redirect.
Why can't you just simply render the meeting ID to a hidden field in your View form? You're already adding it to the model. Alternately, add it to your route as a parameter.
I prefer to maintain that kind of data in the page itself. Render meetingID as a hidden input, so it gets submitted back to the controller. The controller handling the post can then feed that meeting ID back to whatever view will be rendered, so that the meetingID basically gets passed around as long as you need it.
It's kind of like the difference between storing a value in a global variable before calling a method that will operate on it, vs. passing the value directly to the method.
I would suggest MvcContrib's solution:
http://jonkruger.com/blog/2009/04/06/aspnet-mvc-pass-parameters-when-redirecting-from-one-action-to-another/
If you don't want full MvcContrib, the solution is only 1 method + 1 class that you can easily grab from MvcContrib sources.
The TempData property value is stored in session state. The value of TempData persists until it is read or until the session times out. If you want pass data one controller view to another controller view then you should use TempData.
Use Session when the data need for the throughout application