In MVC 4 application while defining routing I can provide a list of default parameters. What value shall I provide for optional parameter: UrlParameter.Optional or empty string?
Examples:
routes.MapRoute("simple", "{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = UrlParameter.Optional});
routes.MapRoute("simple", "{controller}/{action}/{id}",
new {controller = "Home", action = "Index", id = ""});
Is there any difference between id = "" and id = UrlParameter.Optional in above examples?
Please note that some controller actions will be using id (of type string) and some will be parameterless.
The difference is subtle and but almost unimportant
UrlParameter.Optional means a null will be passed to the Action Method in lieu of a value.
id = "" means a default value of "" (not null) will be passed to the Action Method.
In both cases, not including an id parameter in your route will NOT stop the MVC framework from finding the right method.
In the case of UrlParameter.Optional, you should make all relatable Action Methods take a nullable parameter
Type matters
You should NOT apply id="" to routes that use ints.
Related
I use the Url.Action method to generate a Url string.
Thats the result:
"/Home/GetRejectTest/0?IsSelected=False"
The controller and action name are correct but the query parameters are screwed up. Is this because The action does not have a RouteAttribute thus query parameters are generated?
My action:
public ActionResult GetRejectTest(Test test)
{
return new EmptyResult();
}
Test class has those 3 properties Id, Name, IsSelected.
My route definition:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The url your generating (/Home/GetRejectTest/0?IsSelected=False) is correct for your route definition. You passing a new instance of Test to the Url.Action() method, which
Internally builds a dictionary based on the name and value
(using.ToString()) of each property in your model - i.e.
controller=Home, action=GetRejectTest, id=0, Name=null, IsSelected=False
Then searches your route definitions for a match which it finds
(url: "{controller}/{action}/{id}") and updates the placeholders
(which at this point generates /Home/GetRejectTest/0) but your
route definition does not have url parameters for Name and
IsSelected so these are added as query string parameters (because
Name is null, a query string for that propery is not generated)
so the result is now /Home/GetRejectTest/0?IsSelected=False
You have not indicated what result you're actually expecting, but creating specific route definitions will solve most cases. For example if you want
/Home/GetRejectTest/0/false
or /Home/GetRejectTest/0/false/someName if the value of Name is not null, then you can create an additional route (which must be before the default route)
routes.MapRoute(
name: "Test",
url: "Home/GetRejectTest/{id}/{isselected}/{name}",
defaults: new { controller = "Home", action = "GetRejectTest", name = UrlParameter.Optional }
);
Note that because Name is typeof string and therefore can be null, the {name} placeholder needs be the last one and marked as UrlParameter.Optional (otherwise it will revert back to using query string parameters)
Here is my route, the only required param is the controller
routes.MapRoute(
"countryoptional/controller",
"{country}/{controller}/{pagelabel}/{page}",
new { action = "index", country = UrlParameter.Optional, pagelabel = UrlParameter.Optional, page = UrlParameter.Optional },
new
{
pays = #"$|^(france|belgium)$",
controller = #"^(car|boat)$",
pagelabel = #"^$|page",
page = #"^$|\d{1,6}"
}
);
I'm expecting the following URLS to work with :
/car/
/car/page/2
/france/car
/france/car/page/2
It kind of works :
Url.Action("index", "car", new { country= "france", pagelabel = "page", page = 2} )
Will produce : /france/car/page/2
BUT
If I want an url without a country the view action respond but a constructor like
Url.Action("index", "car", new { pagelabel = "page", page = 2} )
will produces this link : //car/page/2
I get this double slash "//car" so it breaks the link of course.
I suspect the fact it does not like the possibility of the {country} parameter preceding controller optional in the {country}/{controller}/... url definition
I don't want to complicate my route config and having another route declaration
There must be a way, what I'm I doing wrong ?
Optional parameters must follow any required parameters. There's no way around this that I know of. The same limitation applies everywhere else (your method definitions, etc.).
Just repeat the route and have one with a required country and one without any country. MVC will work out which one to use.
I have a controller class Movie. One of its action method is given as follows:
public string ActionMethod(string id)
{
if (id == null)
{
return "null";
}
if (id == string.Empty)
{
return "empty";
}
return "neither null nor empaty";
}
Is it possible to pass an empty string to an action method with a routed URL segment rather than a query string?
Note that http://localhost:21068/Movies/ActionMethod?id= can do that but it uses a query string. In addition, it is not allowed to modify the action method. :-)
I'm not clear about what you're trying to achieve, but you can probably do it by specifying routes appropriately in Global.asax.cs. As a contrived example, the following:
routes.MapRoute(
"",
"{controller}/{action}/id/{id}",
new { controller = "Home", action = "Index", id = "" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
lets you use:
http://localhost:21068/Movies/ActionMethod - id is null
http://localhost:21068/Movies/ActionMethod/id/ - id is an empty string
http://localhost:21068/Movies/ActionMethod/id/123 - id is a nonempty string
If you state what URLs you want to allow and how to map them, someone will no doubt suggest how you can set up your routes.
Dont pass any querystring if ur ID is empty. like
http://localhost:21068/Movies/ActionMethod
If you can't use a query string, have you considered using a form? I haven't tested this, but give it a go:
#using (Html.BeginForm("ActionMethod", "YourControllerName", "GET")) {
<input type="text" name="id">
<input type="submit" name="submitForm" value="submitForm" />
}
Reference: http://msdn.microsoft.com/en-us/library/dd460344(v=vs.108).aspx
I think you can pass nullable parameter like:
public string ActionMethod(string? id)
and than don't pass any query string as:
http://localhost:21068/Movies/ActionMethod
I'm new to MVC land, and have an app that i'm working on. i have 2 different links with 2 routes in my global which are fairly similiar
route 1
routes.MapRoute("Category", "Movies/{category}/{subcategory}",
new { controller = "Catalog", action = "Index", category = "", subcategory = "" });
route 2
routes.MapRoute("Movie", "Movie/{movie}",
new { controller = "Movie", action = "Index", movie = "" });
When i call an actionlink for the first route it creates it as i would think it should:
.../Movies/Category/SubCategory
however when i create my second link it populates it like this:
.../Movie?movieId=ff569575-08ec-4049-93e2-901e7b0cb96a
I was using a string instead of a guid before and it was still doing the same i.e.
.../Movie?movieName=Snatch
my actionlinks are set up as follows
<%= Html.ActionLink(parent.Name, "Index", "Catalog",
new { category = parent.Name, subCategory = "" }, null)%>
<%= Html.ActionLink(movie.Name, "Index", "Movie",
new { movieId = movie.MovieId }, null)%>
My app still works, but i thought this behavior was strange. any help would be great.
Thanks!
routes.MapRoute("Movie", "Movie/{movieId}",
new { controller = "Movie", action = "Index", movie = "" });
Should the route text not match the name of the property which you are submitting to the mvc link?
The problem is that when you call ActionLink, the routing system can't figure out which of the two routes to use, so it chooses the first. The solution is to use RouteLink instead of ActionLink. RouteLink lets you specify the name of the route to use when generating the URI. Then there is no ambiguity as to which route to use. I think that ActionLink is obsolete. I can think of no reason to use it in lieu of of RouteLink.
However, you may still have a problem when the user submits links. In that case, use route constraints to enforce the selection of the correct route.
Andrew is correct (up-voted) that the tokens you use in ActionLink/RouteLink and the route itself must match.
On an ASP.NET MVC (Beta) site that I am developing sometimes calls to ActionLink will return to me URLs containing querying strings. I have isolated the circumstances that produce this behavior, but I still do not understand why, instead of producing a clean URL, it decides to using a query string parameter. I know that functionally they are the same, but for consistency (and appearance) of the URLs this is not what I want.
Here are my routes:
routes.MapRoute(
"Photo Gallery Shortcut",
"group/{groupname}",
new { controller = "Photos", action = "All", Id = "" });
routes.MapRoute(
"Tagged Photos", //since the Tagged action takes an extra parameter, put it first
"group/{groupname}/Photos/Tagged/{tagname}/{sortby}",
new { controller = "Photos", action = "Tagged", Id = "", SortBy = "" });
routes.MapRoute(
"Photo Gallery", //since the Gallery's defualt action is "All" not "Index" its listed seperatly
"group/{groupname}/Photos/{action}/{sortby}",
new { controller = "Photos", action = "All", Id = "", SortBy = "" });
routes.MapRoute(
"Group", //<-- "Group" Category defined above
"group/{groupname}/{controller}/{action}/{id}",
new {controller = "Photos", action = "Index", Id = ""});
Now the problem only occurs when I am looking at the view described by the route named "Tagged Photos" and execute ActionLink via:
Html.ActionLink<PhotosController>(p => p.All((string)ViewData["group"], ""), "Home")
Which produces the URL:
http://domain/group/GROUPNAME?sortBy=
From any other view the URL produced is:
http://domain/group/GROUPNAME
I have pulled down Phil's ASP.NET Routing Debugger, and everything appears in order. This one has me stumped. Any ideas?
Not sure why different views are producing different URLs.
But you can get rid of that sortBy param by assigning a default value to the first route.
new { sortBy = "" }
During generation, if sortBy matches the default, the route engine will skip that parameter (if it's in the query string).
You're going to have to use named routes here, not action routes, because of the way routing works in ASP.NET, because it does "first match", not "best match".
I think it is picking up your first Route. It too has the action All. And because the sortby is not specified it is exposing it as a querystring parameter
This will still work with the action method 'All' on the PhotosController, because it just fills the sortby parameter with the query string value.
In the Route Debugger is it executing the 3rd route or the 1st?