I have a call that looks like this:
<%= Html.RouteLink(item.displayName, "DisplayCategory", new { category = Html.Encode(item.displayName), subcat = item.searchName }) %>
and I'm getting html that looks like this:
http://localhost:1485/Home/ShowCategory/Electronics%20&%20Photography?subcat=electronics-photo
Why does the URL end with "?subcat=electronics-photo" rather than "/electronics-photo" ? Is it somehow related to the route definition?
routes.MapRoute(
"DisplayCategory",
"Home/ShowCategory/{category}/{tags}",
new { controller = "Home", action = "ShowCategory", category = "", tags = "" }
);
Any clues would be appreciated!
MVC routing tacks on a query string if it can't match one of the parameters in the route definition. Try adding subcat to your route:
routes.MapRoute(
"DisplayCategory",
"Home/ShowCategory/{category}/{tags}/{subcat}",
new { controller = "Home", action = "ShowCategory", category = "", tags = "", subcat = "" }
);
I'm just taking a stab but it looks like you're using the MVC framework.
In it every controller has an action, in this case ShowCategory, and by default they take a query string, in this case category. MVC purposefully abstracts the folder sturcture. I believe a MVC app will always have a URL of this type and depth domain.ext/Controller/Action?queryString.
I think the question may be whether or not the subcat is set to properly. A little more info/code might be hopeful.
Also sorry for not addressing the routing portion of your question.
Related
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’ve got the following code (from a partial view), which creates a list of links enabling me to filter the items listed within my index page according to the letter they begin with:
#{
string letters = "abcdefghijklmnopqrstuvwxyz";
}
<ul>
<li>#Html.ActionLink("0–9", "Index")</li>
#foreach (char c in letters.ToCharArray()) {
<li>#Html.ActionLink(c.ToString().ToUpper(), "Index", new { letter = c.ToString() })</li>
}
</ul>
The first link in the list is for cases where the items begin with a number. I’ve also got the following routes set up in my Global.asax file:
routes.MapRoute(
"",
"artists",
new { controller = "Artist", action = "Index" }
);
routes.MapRoute(
"",
"artists/{letter}",
new { controller = "Artist", action = "Index" },
new { letter = "[a-z]" }
);
So the paths for the links that the above partial view creates should look something like:
/artists
/artists/a
/artists/b
…
and so on. What I’m getting though is odd in that it’s ignoring the routing and creating links like:
/artists
/artists?letter=a
/artists?letter=b
…
Now, if I swap around the order of the routes, it produces the links as I want them, but then I run into another problem. If I then navigate to /artists/a (or any other letter), the first link in the list picks up the current value of the letter parameter and appends it to the list, so I end up with links like:
/artists/a
/artists/a
/artists/b
…
As you can see, that makes it impossible to get back to the index with no filtering. Any ideas as to how I can either fix the routing so that the links are created correctly without the parameters being passed as a query string, or fix the ActionLink as to not append the current parameter?
Make only one route and set the {letter} parameter as optional.
routes.MapRoute(
"artists",
"artists/{letter}",
new { controller = "Artist", action = "Index", letter = UrlParameter.Optional },
new { letter = "[a-z]" }
);
EDIT:
Have a look at this post.
EDIT2:
Another possible solution would be:
routes.MapRoute(
"artists",
"artists/{letter}",
new { controller = "Artist", action = "Index", letter = "0" },
new { letter = "[0a-z]" }
);
#Html.ActionLink("0–9", "Index", new { letter = "0"} );
In ASP.NET MVC, is it possible to define routes that can determine which controller to use based on the data type of part of the URL?
For example:
routes.MapRoute("Integer", "{myInteger}", new { controller = "Integer", action = "ProcessInteger", myInteger = "" });
routes.MapRoute("String", "{myString}", new { controller = "String", action = "ProcessString", myString = "" });
Essentially, I want the following URLs to be handled by different controllers even though they have the same number of parts:
mydomain/123
mydomain/ABC
P.S. The above code doesn't work but it's indicative of what I want to acheive.
Yes, if you use constraints:
like so:
routes.MapRoute(
"Integers",
"{myInteger}",
new { controller = "Integer", action = "ProcessInteger"},
new { myInteger = #"\d+" }
);
If you put that route above your string route (that doesn't contain the constraint for #"\d+"), then it'll filter out any routes containing integers, and anything that doesn't have integers will be passed through and your string route will pick it up.
The real trick is that Routes can filter what's coming through based on Regular Expressions, and that's how you can determine what should pick it up.
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?