I'm curious how this works. In MVC you can call View() and pass a model as a parameter, but RedirectToAction (one of its incarnations at least) takes a 'routeValues' object, which appears to be the closest match.
If your model is passed in this parameter will that model type be available in the subsequent action method? Or are there caveats involved that might prevent accurate translation in some circumstances?
If you need to pass in some-what complex objects to an action after a redirect, you probably want to use either a Session or TempData:
From "What is ASP.NET MVC TempData"
ASP.NET MVC TempData dictionary is used to share data between
controller actions. The value of TempData persists until it is read or
until the current user’s session times out
By default TempData uses a Session to persist the information, however, as with much of MVC, this is an extensibility point, where you can plug in a Cookie-based provider if you prefer.
You cannot pass a model object in there but you can pass individual properties that will map to a model in the action that you redirect to.
That works by building up the url to redirect to using the properties, and the model binder in the receiving action.
Redirect... methods cause client-side-and-back trip, so - no, the model will not be available.
I think this is what you want :
Save your model in a Tempdata
RequestModel rq = new RequestModel()
....assign something to your model..
TempData["request"] = rq;
return Redirect("RequestAcknowledgement");
Now create an Action Result for the view you are redirecting to and pass your TempData back to a model. Then return the model to a view.
public ActionResult RequestAcknowledgement()
{
RequestsModel request = (RequestsModel)TempData["request"];
return View(request);
}
Related
I'm currently using MVC5.
Imagine the scenario where one controller ActionA does its work and the redirects to another controller ActionB but also wants this second method to display a message on its related view.
If Controller ActionA sets the ViewBag.Message and then calls RedirectToAction, when ActionB starts, the value of that Message is gone.
What's the best way to pass a message from one action controller to another, without using Session ??
You can use TempData:
Action A:
TempData["Message"] = "Hi";
Action B:
var message = TempData["Message"];
Once you call the getter in Action B, the information will be automatically removed from memory.
This article is a really good explanation of the various persistence techniques available in ASP.NET MVC.
You say no session, but TempData can be a good place depending on what you're passing. It's essentially Session except that the item will be removed from Session once you've accessed it. TempData actually uses session by default unless you write your own provider.
Passing it as an option in the query string, or passing it as a parameter in the routing (similar to what AJ says)
Other than that you've got the standard run of the mill options that are provided in ASP.NET. HttpContext.Items or maybe HttpContext.Cache. But both of those are shared across the entire application domain so management can get tricky.
Remember, web is supposed to be stateless. So if it's really important for that message to get there, you probably want to put it in the URL somehow (query string or routing), or use a database.
I would put an optional argument on the method signature for ActionB, for example:
public ActionResult ActionB(string message = "")
Note that optional parameters need to be last in your parameters list.
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.
public ActionResult RenderMyThing(IList<String> strings)
{
return View("RenderMyView");
}
How do I pass in strings?
routes.MapRoute("MyRoute", "RenderMyThing.aspx", new { controller = "My", action = "RenderMyThing" });
Is there a way I could pass in strings here?
Secondly, how does ASP.NET MVC know that action is my action, and controller is my controller. Like I saw this in samples, and it does work, but isn't it just an anonymous object with no type?
This is the provenance of model binding: the framework needs to have some instruction as to how to turn a "request", which comes out of the routing context, query string, forms collection, etc., into the parameters that your action method wants.
The DefaultModelBinder will generate a list if it sees that you have multiple key-value pairs with the same key (and appropriately typed/convertible values) - for the details, Phil wrote a good post about this:
If you need fancier binding requirements, you can implement a custom model binder and explicitly define how route values and the other bits get translated into objects (or collections of objects).
Just wondering, I strongly type these views in ASP.NET MVC and then use Request.Form on the submit controller to get the data out, validate it, put it in an object, send to database. Is there a way I can just send the object back from the View page since it is strongly typed instead of doing all this crap to just end up with an object again since I just started with one anyways?
You mean, model binding?
[AcceptVerbs (HttpVerbs.Post)]
public ActionResult UpdateUser (User user)
{
SaveUpdates ();
return View();
}
This will automatically initialize the User properties with the form values with the same names.
Look at this answer: ASP.Net MVC Custom Model Binding explanation
(source: odetocode.com)
[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