Working with tempdata in mvc - asp.net-mvc

As I have read that once you set a tempdata, it will last till next request and if you need to use it more then we need to use keep. But in this situation there is somewhere my tempdata is being lost.
The scenario is below:
I have a view and corresponding to that I have a action method in my controller and here I just set a tempdata as below:
Controller class:
public actionresult myview()
{
tempdata["Empid"]= sourceid;
}
The view consists of several renderAction as below and all these actionmethods in controller return some partialviews
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
#html.renderAction("details","mycontroller")
Now in partialviews, I have several ajaxified calls suppose in one of the partialview , I have a post method using ajax like below:
$.post("action", "controller",{}});
Please ignore syntactical mistakes as I only have problem in understating the logic of tempdata.
So, coming to above, now the post methods have actionmethods that uses the tempdata that i have set when my view page loads i.e tempdata["Empid"] because this tempdata is needed to get details of employee.
So, it gets the data, reurn json formatted data and I show it in view perfectly.
Uptill here everything is fine. Now, I have one of the partialviews that uses the ajax post to hit controller which is not the same controller but a different cs file. Here this tempdata goes off.
Why is it happening so..

TempData is designed for a short life by default. So the data you set to TempDataDictionary object persists only from one request to the next request. After that it is not going to be available.
You can use the TempDataDictionary.Keep() method to persist the value for the next request again.
public ActionResult Index()
{
TempData["Message"]="Hello";
return View();
}
public ActionResult GetCustomer()
{
var msg = TempData["Message"] as string;
TempData.Keep("Message");
return View();
}

Related

ASP.Net MVC - What is the recommended way to retain form values across different controllers?

Let's say I have a HomeController which has an Index action, in the Index.cshtml View I will be posting back to an action in another controller (DocumentsController), after the action is completed I redirect back to Home/Index.
What is the recommended/cleanest approach to maintain the form values that the user has submitted in the Index.cshtml view? Given that it is being redirected from another controller?
EDIT: I'm presently using RedirectToAction:
return RedirectToAction("Index", "Home");
So using this approach how can I retain form values?
You can store the data in TempData or Session, call RedirectToAction, and then retrieve the values from TempData or Session again.
TempData is special. It stores stuff in Session, however, the data stored through TempData is only kept for the current request and a subsequent request. After that, the data is thrown out. It sounds well-suited for what you need, but if you need the data to stay around longer, just use Session.
public class HomeController : Controller
{
public ActionResult Index()
{
var someData = TempData["SomeData"] as string; // can be anything, using a string as an example;
return View(someData);
}
}
public class DocumentsController : Controller
{
public ActionResult DoSomething()
{
TempData["SomeData"] = "Hello, world!";
return RedirectToAction("Index", "Home");
}
}
When you first visit Home/Index, "SomeData" will be missing (null). When you visit Documents/DoSomething, it will set "SomeData" to a string, then redirect you to Home/Index. At that point, Index will see the string we placed in "SomeData" and you can use it in your Index view. After that point however, all temp data will be cleared out.
So, for example, if the user refreshed Index after the redirect a bunch of times, the temp data would be missing during the refreshes. If that is not acceptable, then don't use TempData, but keep it in the Session instead.

How can ViewBag data be saved after a form post?

So I have a ViewBag.Something and this data is randomly generated. In my view, I set this to a label like so #Html.LabelFor(m => m.Something, (string)ViewBag.Something). This works out well but when I submit the form there could be errors and if there are errors, I need this label to remain the same, I don't want dynamic/random data anymore so I wouldn't call the controller method that generated this ViewBag. Is there a way to retain this value without having some private variable in my controller? Some nice way that MVC/Razor does it?
Option 1:
Pass the value of "ViewBag.Something" to the Controller by using route Values:
#Html.ActionLink("ButtonText", "ActionName", new { Something = #ViewBag.Something })
Option 2:
You can use TempData.
public ActionResult Index()
{
var Something = "YOURVALUE";
TempData["Something"] = Something;
.......
}
public ActionResult OtherAction()
{
var Something = TempData["Something "];
...........
}
Passing State Between Action Methods
Action methods might have to pass data to another action, such as if an error occurs when a form is being posted, or if the method must redirect to additional methods, as might occur when the user is directed to a login view and then back to the original action method.
An action method can store data in the controller's TempDataDictionary object before it calls the controller's RedirectToAction method to invoke the next action. The TempData property value is stored in session state. Any action method that is called after the TempDataDictionary value is set can get values from the object and then process or display them. 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.
In the get, set up a model, set it dynamically and when return view() is being executed, do return view(model). Then in the view, set up a hidden field that can keep on passing the value needed. I chose to go this route because I don't have to worry about any server code to make this work on a post and I don't have to worry about any sessions.
Displaying message in viewbag after posting (I user this method)
ActionResult SubmitUser(){
ViewBag.Msg =TempData["Msg"];
return view();
}
[HtttpPost]
ActionResult SubmitUser(){
TempData["Msg"] ="Submitted Successfully"];
return view();
}
The Value is send to get method..

How to re-use model data on post back with MVC

I'm passing structured data to my MVC page when it loads initially. After the user submits a contact form, I want to re-use the same data (I just "leave" the same page up) so I don't have to hit the database again. I declared a variable global to the controller to store the model data, but it's null at the end of the post back, so it looks like I can't re-use it there.
Seems like this would be a typical scenario. How do I handle it?
If you are wanting to reuse viewmodel or other retrieved data that is not going to be part of the postback, you can either
a) Output it in hidden fields so that it is posted back to your action (meh) or
b) Store the object(s) in Session so that it will be available to any other controllers/actions in your application. If you are worried about memory, you could delete that session variable after you reuse it if you are not going to need to use it again.
On your initial page load, check if the session variable exists, if it does, you are good - else populate it.
Oh and why the global variable thing isn't working -> a controller is new'd up for each request (assuming using the default controller factory) and as such any global variables in the controller will be reset on each request.
public ActionResult Foo()
{
var model = GetModelFromDB();
Return View(model);
}
[HttpPost]
public ActionResult Foo(Entity model)
{
Return View(model);
}
Asp.net-mvc is stateless so each HTTP request has a different context, and each time you hit the controller all it's data reset in the constructor, this why you get null.
You can get the model in the post if it's properties are within the submitted form .
If you really don't want to leave the page you are on, and don't want to post all the other data back as KMan suggests, but still want to capture the users contact information/data you could post the contact info using ajax.
If you have your view model as an argument to your method, you can just return it to the view on postback. Ex:
public ActionResult TestAction(MyViewModelType testViewModel)
{
//Do logic
return View("view",testViewModel);
}
Note that you have to have the data inside the form you are posting.

Show partial view based on parameter

In the process of updating a C# MVC 2.0 application!
I have a view “Signup” and another view “ForgotPassword”.
Each view have a with a submit button.
Each form is submitted to the same Controller but to two different ActionResult:
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{…}
[HttpPost]
public ActionResult ForgotPwd(ForgotPasswordModel forgotPasswordModel)
{…}
Upon completion my goal is to redirect the user to a “thankyou” page but based on where the user is coming from (either Signup or ForgotPassword) I wish to display a particular message (or a different UI).
Inside the same Controller, I created a “Thankyou” ActionResult:
public ViewResult Thankyou()
{
return View();
}
I was thinking of adding a parameter to my Thankyou() method which would allow me to know where the user is coming from (Signup or ForgotPwd). From there, make the “thankyou” page display the appropriate UI/message.
I’m looking for a clean and simple solution.
Should I create two View User Controls and show the appropriate one based on the parameter being passed?
In addition, instead of having an “ActionResult” for my Thankyou() method couldn’t I use a “PartialViewResult” ?
EDIT:
I was actually considering something along those lines…
Where ThankyouType is an Enum.
[HttpPost]
public ActionResult Signup(SignupModel signupModel)
{
//Validation code...
return View("Thankyou", ThankyouType.SignupDone);
}
[HttpPost]
public ActionResult ForgotPassword(ForgotPasswordModel forgotPasswordModel)
{
//Validation code...
return View("Thankyou", ThankyouType.ForgotPasswordDone);
}
And then have my “Thankyou” ViewResult like this:
public ViewResult Thankyou(ThankyouType type)
{
return View(type);
}
Doesn’t seem like I can create a strongly typed view based on Enum (unless I’m wrong).
Perhaps I’ll read more on PartialViewResults and/or find examples…but then again, I could be completely wrong.
I would personally give the ThankYou view a model that has the message you want to display, and have your two controller actions render the ThankYou view directly on success rather than calling a ThankYou action.
However, if you're sure you want a redirect, you may consider using the TempData collection to store a message or a key of some kind. The ThankYou controller can then retrieve this value and pass it to the View. This situation is what TempData was made for.
Edit
There's no reason you shouldn't be able to use an enum value as your model type, but if that gives you trouble you should at least be able to create a model type that has an enum property on it.
The strategy of sending the ThankYouType as part of the redirect request would work just fine, if that's what you prefer. The only potential downside is that it would look like this in the URL:
http://domain.com/controller/ThankYou?type=ForgotPasswordDone
I have no real arguments against it. There are lots of options. Use the one that feels best to you.

Asp.net mvc: Posting Back from the View

Is it considered better practice to post back to the same controller that did the rendering and redirecting from original controller if necessary? Or is it just the same if one jumps to different controllers from the view?
I create two overloaded actions in the controller, one to render the input form using an HTTP GET and the other to process the form post using an HTTP POST. Something like this:
public ViewResult Foo()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ViewResult Foo( FormCollection form )
{
// process input
if (inputOK)
return RedirectToAction("Index");
return View();
}
The benefit of doing it this way is that if there's an error, the view gets re-rendered with any error and validation messages. If it's successful, there's a redirect to another action, which avoids the duplicate posting warning on browsers if a user refreshes the page - see Post/Redirect/Get on Wikipedia and this blog entry by Stephen Walther.
There are alternatives to taking a FormCollection, e.g. a list of simple parameters or binding to an object. See this article by ScottGu.
I think that the action that is being called should be contained within a relevant controller for that action. If the view needs to call the action it should call it from the relevant controller, not necessarily the controller that it was spawned from.
If you have an inventory controller you don't want to define actions that relate to administration even if an inventory screen might have an administration action on it, as an example.

Resources