Extend #Url.Action to pass multiple actions - c#

I'm attempting to use #Url.Action to pass multiple parameters through the URL in such a way I can read in the extra parameters using the RouteAttribute
<li><a class="survey-button" href="
#Url.Action("Survey",(Model.SurveyID).ToString(),"Page"(Model.PageNumber).ToString())
">Previous</a></li>
//localhost:8080/Survey/1/Page/1
[Route("Survey/{surveyID}/Page/{pageNumber}")]
public ActionResult Page(int surveyID, int pageNumber)
{
...
I realize I can pass these via a query string, but for cleanliness reasons this is not preferred.

You need to wrap your parameters in a RouteValueDictionary or an anonymous object (easier). I am assuming that your controller name is SurveyController.
#Url.Action("Page", "Survey", new {surveyId = Model.SurveyId, pageNumber = Model.PageNumber})

Related

Parameters for Controller from Html.ActionLink

On the Home View I'm generating a number of links:
<ul class="nav navbar-nav">
#foreach (var item in ViewBag.RegList)
{
<li>#Html.ActionLink((string)item.registryName, "Index", "Registry", new { item.registryName }, new { item.registryID }) </li>
}
</ul>
I don't get - how do I set params in ActionLink for my controller and where they go from there?
That's how I defined Index in me controller:
public async Task<ActionResult> Index(object attr)
But in attr goes only object, which when casted to string becomes null. If the orgignal type is string - then also null.
How do I transfer a parameter? Or I'm casting value to the wrong type?
Also I don't understand - what must fourth parameter of ActionLink (routeValues) be?
Method that I'm using: https://msdn.microsoft.com/en-us/library/dd504972(v=vs.108).aspx
Or this one: https://msdn.microsoft.com/en-us/library/dd493068(v=vs.108).aspx
If you look at the created link they will contain a set of query string parameters
"https://some.where/controller/SomeAction/7788?extraParam1=foo&extraParam2=bar"
The standard routing config of MVC makes the parameter "id" part of the local path ("7788" in the example), whereas additional parameters are added to the query string (after the question mark).
Your method signature to the action should be something like
public async Task<ActionResult>
SomeAction(string id, string extraParam1, string extraParam2)
to get the parameters in my example link.

Passing multiple multivalued parameters to a MVC controller from different search form

I have a website with two search forms, both calling the same controller and action. First form is for cars, second for motorcycles. Each form has multiple search filters. These filters are multivalued.
My route file:
routes.MapRoute("Cars",
"search/cars",
new { controller = "Search", action = "Index", SearchType = "Cars", Param1 = "", Param2="" }, null);
routes.MapRoute("Motorcycles",
"search/moto",
new { controller = "Search", action = "Index", SearchType = "Moto", Param3 = "", Param4="" }, null);
So calling "mywebsite.com/search/cars?Param1=BMW&Param1=VW" should get me these values into my controller:
SearchType = "Cars"
Param1[] = {"BMW", "VW"}
Is there any way to avoid having action in Search controller declared as:
public ActionResult Index(string SearchType, string Param1, string Param2, string Param3, string Param4){}
But instead have one params[] variable which would then contain key value pairs? Parameters in both cases have different names, so I can't always use the same name. Also each search page has different number of parameters.
You may want to consider using JSON and doing a POST with a JSON object. If you're method is going to take a variety of parameters to the point where it could have 3-4+ params, then you should reconsider how the data is transferred. Perhaps create a model for the search that has the filters as fields? You could then just accept the model as an object and handle it that way.
You should also consider using two different actions on the Search controller. Even though you're "searching", you've stated that each form handles different data, which means you will probably need to handle the search differently. Maybe use a Cars action and a Moto action?

How to pass routeValues that contains hyphen via actionlink in asp.net mvc 5

I have an actionlink in view, I need it to pass parameter containing hyphen (-). Changing the name convention is not possible. How do I do this?
<li>#Html.ActionLink("abc", "abc", "abc", new { area = "",sap-ie="Edge" }, new { id = nav_abc"})</li>
This one gives me an error "Invalid Anonymous Type Declarator" since it contains hyphen. Basically I need the actionlink to generate html like below.
<a href=".../abc?sap-ie=Edge" id="nav_abc" >abc</a>
If you are sure the url won't change much from the structure you've specified you could use an anchor tag and build the url from Url.Action.
<a href='#Url.Action("abc", "abc")?sap-ie=Edge'>abc</a>
The whole point of htmlhelpers are to help generate html anyway .. so if its getting in the way, you can drop down to html proper and just get it done.
Just wanted to point out that it's not that the underscore trick only works with data attributes, it's that it only works with passing HTML attributes in general. This is because it makes sense to change underscores to hyphens in the context of HTML, as underscores aren't use in HTML attributes. However, it's perfectly valid for you to have a route param with an underscore, so the framework can make no assumptions about your intent.
If you need to pass route values with hyphens, you have to use a RouteValueDictionary. This is simply a limitation of anonymous objects that can't be overcome.
<li>#Html.ActionLink("abc", "abc", "abc", new RouteValueDictionary { { "area", "" }, "sap-ie", "Edge" } }, new RouteValueDictionary { { "id", "nav_abc" } })</li>
Unfortunately, there's no ActionLink overload that accepts both a RouteValueDictionary for routeValues and an anonymous object for htmlAttributes, so switching one means switching both. You can technically use any IDictionary implementation for the htmlAttributes param, so you may prefer to use just new Dictionary { { "id", "nav_abc" } }. It's up to you.
Have you tried using this overload of the ActionLink method?
#{
var routeValues = new RouteValueDictionary();
routeValues.Add("sap-ie", "Edge");
routeValues.Add("area", "");
var attributes = new Dictionary<string, object>();
attributes.Add("Id", "nav_abc");
}
#Html.ActionLink("Go to contact page", "Contact", routeValues, attributes)

How to pass the parameter to a method when calling in MVC5?

I have a method defined like this:
public ActionResult MatchedBusinesses(List<Business> businesses)
{
if (businesses != null)
{
return View(businesses);
}
return View("NoMatchFound");
}
Then, in my other method I have something similar to this one:
var list = results.AsEnumerable().OrderBy(b => Math.Abs(Convert.ToInt32(temp) - Convert.ToInt32(b.Zip))).Take(5).ToList();
return RedirectToAction("MatchedBusinesses", "Home", list);
The point is that, for the list variable I get the 5 entries that I select using the query. But, then I want to pass that result to my other method, which will be used in other method's view. The problem is, when I call the other method, the businesses parameter is always null. How can I solve the problem? Clearly, I'm not passing the parameter to my MatchedBusinesses method correctly. Any idea, how to solve the problem?
You are using the overload of RedirectToAction where the 3rd parameter is object routeValues. Internally the method uses reflection to build the route values based on the names and the ToString() values of the objects properties.
It works only for properties that are value types, but for properties that are complex types, including collections, it will not bind because (in your case) the value is a string "List<YourAssembly.Business>" and a string cannot be bound to a collection.
You need to persist the collection before redirecting (e.g. database, session, TempData) and then retrieve the collection in the action result.
For example
var list = results.AsEnumerable()....
TempData["results"] = list;
return RedirectToAction("MatchedBusinesses", "Home");
public ActionResult MatchedBusinesses()
{
List<Business> businesses = (List<Business>)TempData["results"];
}
but use TempData with caution (if the user refreshes the browser, the data will be lost). Its better to persist the information to the database with some key, and then pass the key as a route parameter to the MatchedBusinesses() method so that you can retrieve the data from the database.
Edit
What you're trying to do doesn't make much sense. You cannot, and should not, attempt to send large and/or complex objects, like a List, using Route. Instead you should use POST, or follow Stephen Muecke's suggestion in using TempData
However, here's how you can correctly send simple values using RouteValue
You pass parameters by using
return RedirectToAction("ActionName", "ControllerName",
new { paramName = paramValue });
Or if the target Action it's in the same controller
return RedirectToAction("ActionName", new { paramName = paramValue });
The parameter name, is optional. But using
return RedirectToAction("ActionName", new { paramName = paramValue });
Implies that the target action accepts a parameter with the name paramValue.
Here are all the overloads for RedirectToAction
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction%28v=vs.118%29.aspx
Try wrapping your parameter in your return statement in a blank object variable like so:
return RedirectToAction("MatchedBusinesses", "Home", new { businesses = list });
All of the route values for an action have to be one parameter, so it's passed as an object, and then split into the various parameters of the receiving action. Even if you have only one param, it's still looking for an object to split.

RedirectToAction with unnamed querystring parameters

In MVC 2 I have a RedirectToAction call which I need to pass all of the querystring parameters. Unfortunately I can only find a way to pass named querystring parameters is there a way of passing all querystring parameters regardless.
We have one named parameter, id but we just want to append all of the rest onto the end of the URL without setting them explicitly.
return RedirectToAction("index", "enquiry", new { id = enquiryCacheId.ToString()});
You cannot pass COMPLEX objects in URLs, so that kills the option of passing on Complex types in new { }.
One option what you are left with is to encode the querystring and then send that in 'id'. Say for examples, you have querystring as follows name=rami&gender=male. Then you can encode it with HttpUtility.UrlEncode(), then set it to id=[encoded string]. On the other action (retrieving side) you can get id value and then use HttpUtility.UrlDecode() to decode the string. Then finally you can use HttpUtility.ParseQueryString() to split the querystring into NameValueCollection.
If above suggestion is not what you are looking for then. you need to add all querystring parameters to new { } in the RedirectToAction(). If you want to customize it then you might need to go to ASP.Net MVC Source code #CodePlex and make your own builds (which I think not worthy for this kind of requirement).
I have an extension method that I use to modify the querystring of the current URL:
public static string ModifyQueryString(this UrlHelper helper, NameValueCollection updates, IEnumerable<string> removes)
{
var request = helper.RequestContext.HttpContext.Request;
var url = request.Url.AbsolutePath;
var query = HttpUtility.ParseQueryString(request.QueryString.ToString());
updates = updates ?? new NameValueCollection();
foreach (string key in updates.Keys)
{
query.Set(key, updates[key]);
}
removes = removes ?? new List<string>();
foreach (string param in removes)
{
query.Remove(param);
}
if (query.HasKeys())
{
return string.Format("{0}?{1}", url, query.ToString());
}
else
{
return url;
}
}
But, if you need to modify an arbitrary URL, it should be easy enough to modify. You would just need to add a parameter to accept an arbitrary URL, and then instead of getting the URL/querystring from the HttpContext, you just split the passed URL at ?. The rest of the code should work the same.

Categories

Resources