How to redirect users based on what page they came from? - asp.net-mvc-3

I have a page (Controller Action that renders a View) that a user could navigate to from 3 different pages. Basically, a user gets there, does a few selections and clicks on Save button. At this point, I need to redirect the user to where he came from.
I'm wondering, what's the best practice to do that?
I know, for example, I could look in Request, figure out where he came from, then redirect back to there... But that doesn't look like the ideal approach to me.

I'm wondering, what's the best practice to do that?
Pass a returnUrl parameter when invoking this action. Store it in a hidden field if necessary. Make sure that the controller action that performs the validation and needs to redirect gets this parameter as action argument somehow and when the time comes return Redirect(returnUrl);

(Posted on behalf of the question author).
This is what I ended up doing.
Controller:
public ActionResult Index()
{
ViewBag.Referrer = Request.UrlReferrer.LocalPath;
//.....
return View();
}
View (Razor syntax):
Back

Related

Controller redirect back to a POST form

I have a table showing a list of names, with an "edit" button and hidden id value at the side.
Clicking the "edit" button will post the hidden id as a form value and display the edit page so the user can change details of that person. Pretty standard.
When editing the details and submitting I'm using a validator. If the validation fails it needs to go back to the edit page and display the errors. Problem is that the edit page required an Id value via POST method, but the redirect only seems to utilise the GET method which leads to a "Controller Method Not Found" error as there is no Get route set up.
Does anyone know how I can redirect back to the page via POST not GET. Currently my code looks like:
public function postEditsave(){
...
if ($validator->fails())
{
return Redirect::to('admin/baserate/edit')
->withErrors($validator)
->withInput();
}else{
...
thanks
You can use Redirect::back()->withInput();
You may wish to redirect the user to their previous location, for example, after a form submission. You can do so by using the back method
See: http://laravel.com/docs/5.0/responses
You don't need to use POST to go to the edit page. You can use GET and a parameter to the route, check this out: http://laravel.com/docs/routing#route-parameters
You'd have a GET route to show the edit page, and a POST route to handle the request when the user submits the form.
It'll look like this (notice the parameters):
public function getEdit($id)
{
return View::make(....);
}
public function postEdit($id)
{
...
return Redirect::back()->withErrors($validator)->withInput();
}
if "redirect with POST" is exist, then I don't know it. I recomend you to just use flash data
Redirect::to('user/login')->with('id', 'something');
You can use Redirect::to("dashboard/user/$id")->withErrors($validator)->withInput();. You should use double quote to pass parameter if there is any errors with validation.

Back Button Clicked and Error Messages on Previous Page Still Display

I have a very simple 1 page form using ASP.NET MVC 3.
It has 3 inputs. If the user enters the correct inputs and the database retrieves a pdf, that pdf is displayed in the next page. I have used the PRG pattern, in so far as it is possible in this scenario:
public ActionResult Index()
{
SomeModel model = new SomeModel
{
... properties
};
return View(model);
}
[HttpPost]
public ActionResult Index(SomeModel model)
{
byte[] blob = someService.GoGetDetails(model);
TempData.Add("blobkey", blob);
return RedirectToAction("DisplayPdf");
}
public ActionResult DisplayPdf()
{
return File(TempData["blobkey"] as byte[], "application/pdf");
}
The problem use case is as follows.
User enters incorrect details and clicks Submit button. Red error text displays.
User then enters correct details and clicks Submit button. Pdf displays.
User THEN hits back button. Form displays with previous red error text visible.
A tester has made up a requirement that the red text should not be there when the back button is clicked.
Seems easy. Until you try. Does anyone have the magic bullet for this.
One thing I tried as a compromise did not work. That is, I tried to kill caching on the browser with this code inside the DisplayPdf acttion method:
this.ControllerContext.HttpContext.Response.Expires = 60;
this.ControllerContext.HttpContext.Response.ExpiresAbsolute = DateTime.Now.AddSeconds(-1);
this.ControllerContext.HttpContext.Response.AddHeader("pragma", "no-cache");
this.ControllerContext.HttpContext.Response.CacheControl = "no-cache";
It has no effect. Perhaps that works in the webforms world. Not here with the FileResult.
When back button is hit, there is no request to the server. It is all client-side. So, I do have access to javascript. But javascript has no access to the http headers, so there's no way of differentiating from where the page was loaded.
I'm keen to see if this has been solved before. My Googling came up empty.
Thanks
OK. I'm now satisfied. If :
Amazon.com
JsFiddle.net
Outlook.com
Dropbox.com
all exhibit the same behavour, then my work is not falling short of best practice.
Intercepting the navigation buttons of browsers seems very hacky to me. This is one use case where we have to make sure our code does no damage when users do dumb stuff. But resolve elegantly? Probably not a big driver when control is taken out of your hands by the browser.

MVC3 RenderPartial and the ViewBag

I'll try to keep this brief:
In the view
#Html.RenderPartial("myview", Model.SubModel,
new ViewDataDictionary()
{
{ "thing", Model.Thing }
})
In the myview we see that "thing" is avaiable, i.e. this produces the value of Model.Thing in the myview view:
#ViewBag.thing
Great! Simple
But I need to do something with thing (and thing can't be part of SubModel by the way), i.e. access this in my view engine or ideally in the controller, e.g.:
public ActionResult myview(SubModelType vm)
{
var thing = ViewBag.thing; // oh dear this doesnt exist.. but is there when the view is rendered
So my question is, if the ViewBag is available in the resulting myview, it must be being passed around somehow in the httpcontext, or in the controllercontext somewhere right? Does anyone know why it's not available in the controller but is in the view and how I might be able to access this?
Edit
Sorry I missed a vital point here! It's when "myview" is posted back to the controller, invoking an action called myview where I would expect the ViewBag rendered to myview to be available. But of course it's not, it's been used in "myview" and that's it. So if I want to use it in the myview action I'm going to need to store in the ViewBag in that view OR set some value of the viewmodel so that it can be posed back to the action.
Does that make sense?
Sorry I missed a vital point here! It's when "myview" is posted back
to the controller, invoking an action called myview where I would
expect the ViewBag rendered to myview to be available.
Oh no, you cannot be possibly expecting anything like that. That's not how ASP.NET MVC works. When you send an HTTP request to a controller action the default model binder will intercept this request and look in the posted values from the request and bind them to your action argument:
[HttpPost]
public ActionResult myview(SubModelType vm, ThingViewModel thing)
{
...
}
This obviously assumes that those thing values were part of the original request. So for example if you submit a form you should include corresponding fields inside this form that the model binder could use.
Think of it that way: an ASP.NET MVC controller action could be invoked from any client. For example from an iPhone application. And as you know there's no such notion as ViewBag in iOS. All that will happen is that the default model binder will look at the POSTed values and attempt to hydrate the view models that your action is taking as arguments.
If on the other hand you cannot make those thing values as part of the request (by including corresponding input fields in the form) you could only send the ID of this thin from a hidden field and then inside your controller action use this ID to query your underlying data-store to retrieve the thing from the same place you retrieved it initially when you first rendered this form.
Some people might also suggest you storing the Thing inside the Session and then reading the value back from the Session in your POST action. I am not from those people. It's an alternative approach though.

How to prevent redirection on form submission in ASP.Net MVC 3, and just stay on the page?

I have two forms in one View. One of them does the job of uploading pictures to the database.
I need the whole page -and the data the user has typed into the "other form"- to remain untouched, meanwhile the user could also upload pictures. But it doesn't work.
The problem is that when the user submits the photos, the whole page changes. And worse than that, the new page only contains the "photo uploading" form !! Because upon Return View(); of the "upload pictures" Action method, it's View is rendered. :/
Look at the action method:
public ActionResult Upload(IEnumerable<HttpPostedFileBase> files)
{
//Upload the pictures .
return View();
}
Is it possible to achieve the result I need only by changing the return type of the Action method, (maybe ?) in order not to render anything and say just show a message to the user like "Files have been uploaded!" ??
Or should I use Ajax instead ?
Thanks for the advice, in advance ;)
You can't upload files using AJAX but you could use some third-party components that will upload files using hidden iframe which mimics like AJAX. You can google jquery ajax upload plugin.
For the other form you can use Ajax.BeginForm/PartialView to avoid complete refresh.
If the views are strongly typed against a model then you can always pass the model back to the user to "refill" the constant form (probably worst option). Another option (probably best) would be ajax of course.

ASP.NET MVC Redirect to action without a physical redirect

Are it in any way possible to execute another action in the same on in another controller from an action, action filter or in any other way without doing a physical redirect.
The reason for this is that I have a dynamic paging system, where the user will load a url, for an example
/1/some-page-title
This url is maped to the controller “Home” and the action “Element”, this action will then load a row from the database where the element id is “1”. Depending from the data on the element from the database will the page be rendered as a contact form, an image gallery and so on.
Now I could map the paths so
/Page/1/some-title/ will render a normal html page,
/Contact/1/some-title/ will render a contact form
/Gallery/1/some-title/ will render a gallery
But I would prefer the paths to be simple.
There are problems with this answer, it's been a long time since I did anything thing with ASP MVC, so I'm not actually aware of what the problems are.
Unfortunately I can't delete an accepted answer.
So, I'm striking through the answer as it was, if you can actually answer this, or make it better, please do so.
Yes, very simple really :)
Say you're in controller C action A. You want to "redirect" to controller B action Z, just call the other controller action from the current one, returning it's result.
public ActionResult A()
{
return B.Z()
}
You may be looking for Html.RenderAction or Html.Action. However, these are used in the view and not the controller.

Resources