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...).
Related
I'm using ASP.net MVC5 and I have just created a simple search form. Upon submitting, the controller is called with GET parameters.
The thing is that all parameters are sent regardless if the user has filled it resulting in an ugly & bigger URL that is needed.
So, what needs to be done in order that the form won't send null/empty fields?
In my ASP.NET MVC 5 application I want to use some parameters to "survive" several subsequent requests irrespective of whether they were processed in controller or not.
For example, if the request has order/add/1234?promocode=new2014 in it, I want it to stay all the way the user puts together his or her order until he proceeds to check-out. This means, that every action link generated using HTML helpers in my views should contain this parameter.
How can I achieve this?
You could save this parameter in Viewbag and then use it again like
#Url.Action("index",new {promocode = Viewbag.CurrentPromocode})
In an MVC project, I have a partial
#Html.Partial("_MyPartial");
which calls a controller method (using AJAX with jQuery) via URL
'/Home/MyActionMethod?type=myType&sort=az&page=1'
The Home controller contains MyActionMethod, which returns a PartialViewResult.
MyActionMethod has parameters matching those in the URL, which are mapped as per usual.
My question is how to access the top level querystring from MyActionMethod, because I want to include extra values in there? By top level I mean the one seen in the browser, as opposed to the one sent to MyActionMethod from _MyPartial
Many thanks
You have to include them as query string parameters when performing your AJAX call. So when building the link on the server, read the query string parameters and append them to those that you have already.
This is a follow-on to an earlier stackoverflow question (link text).
If you use the default routing definition, which ends with {id}, then if you have an ActionLink whose target is the same method as generated the page the ActionLink is on, the framework automagically includes the id in the callback url, even if you didn't request it.
For example, if you're displaying a page from the following URL:
http://www.somedomain.com/AController/SameMethod/456
and the page cshtml file has an ActionLink like the following:
#Html.ActionLink("some text", "SameMethod", ARouteValueDictionary, SomeHtmlAttributes)
then whether or not you have "id" included in ARouteValueDictionary, it will show up in the generated URL.
This only occurs if you call back to the same method that generated the page in the first place. If you call back to a different method on the same controller the {id} field does not get inserted into the generated URL.
I don't necessarily have a problem with this. But I am curious as to why the designers took this approach.
FYI, I discovered this feature because I'd inadvertently been depending on it in my website design. I have to pass the ID field back to the server, along with a bunch of other information...only I'd never explicitly added the ID information to the RouteValueDictionary. But because most of my callbacks were to the same action method that had generated the page in the first place I was having the information included anyway.
You can imagine my surprise when a new component -- which I was sure was "essentially identical" to what was already working -- failed. But because the new component had a different target action method, the magic went away.
Edit:
Modified the explanation to clarify that including the {id} field in the generated URL is contingent upon calling the same method as generated the page in the first place.
...the framework automagically includes the id in the callback url,
even if you didn't request it.
I would prefer the term "ambiently" over "automagically". You can think of route tokens already in the URL as "ambient" to your HtmlHelper and UrlHelpers.
But I am curious as to why the designers took this approach.
Consider a Controller that groups together, say 5 actions. Those 5 may have links to each other, but not a lot of links outside the group. The simplest overload of Html.Action takes only 2 args: the text to render, and the action name.
This makes shorthand for linking around from action to action within these views. Since they are all on the same controller, and that controller is already in the path for the current action, MVC reuses this value when you don't specify the controller name in the helper method. The same behavior extends to {id}, or any other route token you define.
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.