I have the following scenario:
I have an edit page, which can be called from different pages. These pages could be the detail view for the current entity, or the list view for the entities (with or without a search in the route).
HOW do I cleanly redirect to the original calling page using the MVC framework? Of course I could simply pass the HttpContext.Request.Url value by holding it in my TempData, but that sort of smells, in my eyes (or, err, nose). It's on a lower level than the rest of the code.
Is there a way to get the routevalues for the previous page in a controller context? If I have that, I could store that temporarily and pass that to the redirect.
Do not use TempData when not redirecting. One AJAX request from your edit page, and the TempData will go away.
Tomas is right that a hidden element or query string parameter is the way to go. But make sure you sanitize the value submitted. You don't want to redirect any old site on the web; you need to ensure that the page to which you redirect is part of your sites.
you can always have a hidden form element telling the controller where to redirect when posting a form. when using a get request, you could use a querystring in a similar way. it might not be the most beautiful solution, but it's quite a lot safer than trusting httpreferrer or other headers that could easily be changed (or ommitted) by the browser.
Related
I have a hidden field in the layout page
#Html.Hidden("idmember", "123456");
I want to access this value in my controller's action
public ActionResult Index(string idmember){
//value for test parameter is null
}
When I do viewsouce on the page - the value is there.
What is the right way to access the value from layout page? Thanks,
UPDATED. based on the help from others, I released in order to pass value to the action I need to do a form post (and it works) but I have an actionlink
example:
#Html.ActionLink("View Member", "index", "member",new{idmember="12345"}, null)
This does work and my URL is /member/index?idmember=12345 But I wanted to make the link cleaner instead of passing the value in the querystring I wanted to somehow pass the value as hidden field? or another way to the action? Is it possible?
Regarding your edit: you shouldn't want to. You pass parameters either in the URL or as request body variables (e.g. POST body).
You can circumvent this for example by using the session to store the ID, but this is going to cause unexpected behavior and will break your web application. Session timeouts, users using multiple tabs and users wanting to share links are going to cause problems.
In short: use the URL for what it's meant to do; don't care about arbitrary "cleanliness".
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
How do I can persist data in MVC Razor without using TempData between requests?
I see when we can use TempData from this, but don't want to TempData as it creates a state on the machine.
Thanks, Anish
EDIT: I want to persist the previous sort direction in a View page where a user is allowed to sort fields such as Name, Age etc.
FIX: I fixed it using ViewBag. Previous sort field/direction sent to View from Controller using ViewBag and then passed it back as query string in the next click.
Good FIX: I handled the everything in .js file such as checking and then in setting the previous sort field and previous sort dir in Controller.
This is what I finally did. I used ViewBag to send previous details to ViewPage and did the validation in a .js based on the current user action and passed it back to the controller in form-data.
Maintaining State in client page is something which is breaking the concept of HTTP which is stateless. Why do you want to maintain state ? If you are looking for some solution for Passing some data from your controller action to corresponding view, i would suggest you to go with a ViewModel where you fill the data for the dropdown and send that ViewModel object to the strongly typed view. You will have your data available there. Also you should grab data from your DataLayer ( from tables/ or Cache or etc..) in every request if you want some data.
You may pass a relevant id in the query string to get the corresponding data.
As RTigger mentioned, you may store some data in session. That will be available across all the pages till the life time of that session.
I haven't done a lot of ASP.NET MVC 3 recently, but I think the only real way you can persist data across requests is either with session state, cookies, or by posting data to the server every request.
ViewData, ViewBag, and TempData are all effectively killed at the end of each request, whereas session state, cookies, and post data is made available at the beginning of every request based on information from the client browser.
What particular scenario are you trying to persist data for?
You could pass those values as query string parameters when redirecting.
You can set parameters to hidden input fields if you post the form. But if you gonna call action by HTTPGET then you can pass values by using QueryString parameters.
Perhaps this is impossible, but I figured I would ask anyway. I'm working on an ASP.NET MVC application that uses jquery/AJAX extensively. One of the AJAX tasks that gets performed is a call to controller action that returns a URL to redirect the user to.
What I would like to do is to have the same controller context when making an AJAX call as I do on the current page. The reason for this is because the controller action called by AJAX makes use of the Url.Action() method and I need it to use the same route values as what is currently being used on the current page.
So for example, if a user is currently on: /Site/Search/Advanced/Widgets/Black and Blue/1/Descending, mapping to a route of Site/Search/Advanced/{objectType}/{query}/{pageNum}/{displayMethod}, with {objectType} defaulting to "Cars" (not "Widgets").
I would like a call to Url.Action("Advanced", "Search", new {query="Something else"}) to generate /Site/Search/Advanced/Widgets/Something else/1/Descending.
As it stands, the call will generate /Site/Search/Advanced/Cars/Something else, because the controller does not what context it is in.
My alternative is to specify the additional parameters directly in the Url.Action call, but that would require a lot more complexity with values coming in and out of jquery AJAX through various hidden fields, which would be a huge mess...
Any ideas?
Assuming that you on every ajax call want the route values you haven't specified to be the same as in the original non-ajax request, you could always make use of ViewContext.RouteData to add the extra parameters to the ajax call. When the ajax call is returned, you use the route data to add to any new links in the asynchronously loaded results.
Another way is to use the Session object to keep track of the last request, and change the values if new ones are sent.
On the other hand, I would like to question your goal (if this search scenario is your actual scenario): If I search for something, browse to page 4, and then enter a new search term, I don't expect to go to page 4 of the new search results - I expect the first page (although I do expect that my chosen sorting order is preserved...).
I have a ActionLink, that calls my public ActionResult, and I would like it to return back to the page that it was called from, but how?
There are a couple of tricks that you can use for this.
The simplest is ...
return Redirect(HttpContext.Request.UrlReferrer.AbsoluteUri);
AbsoluteUri may not give you the exact path you are looking for, but UrlReferrer should have the imformation you are looking for. Redirect returns a subclass of ActionResult so it is a valid return value.
Another idea is to base the redirect location off of stored values. This is useful when you are going to make multiple requests before you want to redirect, such as when you validate a form and show validation issues on the first response. Another situation will be when the referrer is not a local site. In either case, your referrer won't be what you want it to and you will need to retrieve the correct location from somewhere else.
Specific implementations include using a hidden input field on your form, session state, pulling a descriminator value from your route data, or even just a more constant value like HttpContext.Request.ApplicationPath.
Good luck.
Keep in mind that due to the state-less nature of the web, your ActionResult isn't "called from" your ActionLink as much it is simply a url that the user-agent requested.
Because of this, the only real "built-in" way you can know where that user was coming from is by inspecting the http Request headers to see what the referring page was:
string referrer = Request.Headers["referer"];
You'd then be responsible for parsing out the Action method from this url, if you were going to call it directly. Be aware that this referrer may not be a link within your own site.