Losing parameter values when using a route mapping for an Action? - asp.net-mvc

I am using MVC3, ASP.NET 4.5, C#, razor and developing on IIS Express.
I have a route:
routes.MapRoute(
"Item_Delete",
"Item/Delete/{id}/{a}/{b}/{c}",
new { controller = "Item", action = "Delete"}
);
I have an Action method:
public ActionResult Delete(int id, int a = 0, int b= 0, int c = 0)
When I comment out the route mapping I have :
http://myserver/Item/Delete/1301?a=8&b=1&c=0
The above querystring returns the values for a, b and c correctly ie
id=1301, a=8, b=1, c=0
However if the routing is active, I get the url converted to :
http://myserver/Item/Delete/1301/8/1/0
But I get
id=1301, a=0, b=0, c=0
in the Action Method which is really confusing me.
Perhaps I have set up my route incorrectly? It seems to be firing as I getting the url formatted correctly. The Action method just does not seem able to extract the correct parameter values from it.
Thanks for any help.
EDIT1
Cause of the issue was due to the interference of another route mapping earlier in the file:
routes.MapRoute("Suppliers", "{controller}/{action}/{id}/{d}/{e}/{f}", new { id = UrlParameter.Optional }, new string[] { "MyApp.MVC3.ED.Controllers" });
The only similarities I can see are:
a) Generic {controller}.
b) Generic {action}
c) Same {id} parameter tag
d) Same number of paramers ie (d},{e},{f} , although different names. So should not interfere?
My solution for now is to put the route before the above one, but I would love to understand why the above interferes. All too much like "magic" for my comfort !!!
EDIT2
On further research it seems that if you have {controller}/{action} type patsh too early on they can cause chaos as it seems MVC will match on just the {controller} regardless of the parameters. So my solution was to use the following format for all my more specific routes:
MyController/MyAction/{id}..., new{controller="MyController","MyAction"}
Seems a bit long winded, but this seems the only predictable way to write my routes.

can you try this.
write route in this way
routes.MapLocalizedRoute("ItemDel", "s/{id}/{a}/{b}/{c}",
new { controller = "Item", action = "Delete", a = UrlParameter.Optional,b=UrlParameter.Optional,c=UrlParameter.Optional },
new { id = #"\d+", a = #"\d+", b = #"\d+", c = #"\d+" },
new[] { "Nop.Web.Controllers" });
and call it from controller like this
return RedirectToRoute("ItemDel", new
{
id =1301,
a=8,
b= 1,
c=0
});

Related

ASP.Net Core MVC Routing Issue

I am working on a project (Developed by using .Net Core), I have set some routes and one of them is not working e.g.
1) routes.MapRoute("HRDetail", "H-R/{TName}/{MId}", new { controller = "ABC", action = "XYZ1" });
2) routes.MapRoute("CL", "{SName}/{CName}/{CId}", new { controller = "ABC", action = "XYZ2" });
I have written the code in the same sequence in Startup class, and my action methods are as follows.
public async Task<IActionResult> XYZ2(string SName, string CName, Int16 CId)
{//for route#2}
public async Task<IActionResult> XYZ1( string TName, Int64 MId)
{//for route#1}
Now I want to hit on XYZ1 by using route#1 and the link (to hit on XYZ1 is being created dynamically) is like this http://localhost:4321/H-R/UK/1234. But the problem is that when i click on this link, it always take me to XYZ2 method.
I didn't set any route on controller or action method level.
Is there any solution plz?
It seems, The route are getting confused. There are two ways you can fix this.
1) in your first route specify the regular expression which will say that first parameter will be a fixed string as H-R
2) in you second route specify the regular expression which will say that first parameter will never be H-R
1st
routes.MapRoute("HRDetail", "{ActionName}/{TName}/{MId}", new { controller = "ABC", action = "XYZ1" }, new{ActionName = "$your regularexpression to include only H-R$"});
OR
routes.MapRoute("CL", "{SName}/{CName}/{CId}", new { controller = "ABC", action = "XYZ2" }, new {SName = "$your regularexpression to exclude H-R$" });
PS: you need to put some efforts for regular expression

In ASP.Net MVC routing, how can you route 2 different paths that look the same, but have different types?

In ASP.Net MVC, I want 2 different routes:
http://mysite.com/foo/12345
and
http://mysite.com/foo/bar
In the class Foo, I have 2 methods that return ActionResult
public ActionResult DetailsById(int id)
{
. . . some code
}
and
public ActionResult DetailsByName(string name)
{
. . . some code
}
How do I set up 2 routes so that if the parameter is an int, it goes to DetailsById, but otherwise goes to DetailsByName?
You can use a route constraint for the first route.
routes.MapRoute("DetailsById",
"foo/{id}",
new { controller = "foo", action = "DetailsById" },
new { id = #"\d+" } // Parameter constraints
);
routes.MapRoute("DetailsByName",
"foo/{id}",
new { controller = "foo", action = "DetailsByName" }
);
The first route will only accept ids that match the regex (which accepts numbers only). If it doesn't match the first route, it will go to the second.
Use something like this:
routes.MapRoute(
"DetailsById",
"Foo/{Id}",
new {controller="Foo", action="DetailsById"},
new {Id= #"\d+" }
);
routes.MapRoute(
"DetailsByName",
"Foo/{Name}",
new {controller="Foo", action="DetailsByName"}
);
Remember that the routes are checked from top to bottom and stop at the first match.
I'm assuming that you already have a default route set up for your id parameter.
The only thing you will need to do is add a map route in your global.asax.cs:
routes.MapRoute(
"Foo_DetailsByName",// Route name
"Foo/DetailsByName/{name}",// URL with parameters
new { controller = "Foo", action = "DetailsByName", name = String.Empty } // Parameter defaults
);
In some cases, this can be accomplished through a route constraint. A common scenario is the ability to have my domain.com/482 behave the same way as my domain.com/products/details/482, where you do not want the 482 to be matched as a controller but as a Product ID.
Route constraints are regular expressions, though, so while you can use regex to match the pattern of the route, you are not actually matching based on data type.
See: http://www.asp.net/mvc/tutorials/creating-a-route-constraint-cs

ASP.NET MVC Map String Url To A Route Value Object

I am creating a modular ASP.NET MVC application using areas. In short, I have created a greedy route that captures all routes beginning with {application}/{*catchAll}.
Here is the action:
// get /application/index
public ActionResult Index(string application, object catchAll)
{
// forward to partial request to return partial view
ViewData["partialRequest"] = new PartialRequest(catchAll);
// this gets called in the view page and uses a partial request class to return a partial view
}
Example:
The Url "/Application/Accounts/LogOn" will then cause the Index action to pass "/Accounts/LogOn" into the PartialRequest, but as a string value.
// partial request constructor
public PartialRequest(object routeValues)
{
RouteValueDictionary = new RouteValueDictionary(routeValues);
}
In this case, the route value dictionary will not return any values for the routeData, whereas if I specify a route in the Index Action:
ViewData["partialRequest"] = new PartialRequest(new { controller = "accounts", action = "logon" });
It works, and the routeData values contains a "controller" key and an "action" key; whereas before, the keys are empty, and therefore the rest of the class wont work.
So my question is, how can I convert the "/Accounts/LogOn" in the catchAll to "new { controller = "accounts", action = "logon" }"??
If this is not clear, I will explain more! :)
Matt
This is the "closest" I have got, but it obviously wont work for complex routes:
// split values into array
var routeParts = catchAll.ToString().Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
// feels like a hack
catchAll = new
{
controller = routeParts[0],
action = routeParts[1]
};
You need to know what part is what in the catchAll parameter. Then you need to parse it yourself (like you are doing in your example or use a regexp). There is no way for the framework to know what part is the controller name and what is the action name and so on, as you haven't specified that in your route.
Why do you want to do something like this? There is probably a better way.

Advanced Routing Behaviour with ASP.NET MVC Routing

Given a url that follows the following pattern:
firstcolor={value1}/secondcolor={value2}
where value1 and value2 can vary and an action method like:
ProcessColors(string color1, string color2) in say a controller called ColorController.
I want the following route evaluation:
URL '/firstcolor=red' results in a call like ProcessColors("red", null)
URL '/secondcolor=blue'results in a call like ProcessColors(null, "blue")
URL 'firstcolor=red/secondcolor=blue' ends up in a call like ProcessColors("red", "blue")
Now from I think this can be achieved with a few routes, something like this
route.MapRoute(null,
"firstcolor={color1}/secondcolor={color2}",
new { controller=ColorController, action = ProcessColors })
route.MapRoute(null,
"firstcolor={color1}}",
new { controller=ColorController, action = ProcessColors, color2 = (string)null })
route.MapRoute(null,
"secondcolor={color2}}",
new { controller=ColorController, action = ProcessColors, color1 = (string)null })
This is sufficient for just 2 colors, but as far as I can tell we'll end up with a proliferation of routes if we wanted to have, say 4 colors and be able to have URL's like this:
'/firstcolor=blue/secondcolor=red/thirdcolor=green/fourthcolor=black'
'/firstcolor=blue/thirdcolour=red'
'/thirdcolour=red/fourthcolour=black'
and so on, i.e. we need to cater for any combination given that firstcolor will always be before 2nd, 2nd will always be before 3rd and so on.
Ignoring my ridiculous example, is there any nice way to deal with this sort of situation that doesn't involve lots of routes and action methods needing to be created?
First of all, if you are going to use that key=value format, then I suggest using QueryString instead of the URL.
But if not, you can do this :
//register this route
routes.MapRoute("color", "colors/processcolors/{*q}",
new { controller = "Color", action ="ProcessColors" });
Then in your ColorController :
public ActionResult ProcessColors(string q) {
string[] colors = GetColors(q);
return View();
}
private string[] GetColors(string q) {
if (String.IsNullOrEmpty(q)) {
return null;
}
return q.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
}
In this case your URLs will be like this :
site.com/colors/processcolors/red
site.com/colors/processcolors/red/green
In the case that we use the wildcard mapping I suppose we lose the ability to use Html.ActionLink to build our URL's for us?

ASP.NET MVC: action methods with one param not named ID and non-integer

Consider an ASP.NET MVC 1.0 project using the Areas convention as described on this Nov. 2008 Phil Haack blog post. This solution works great once it's set up!
My trouble is starting thanks to my limited knowledge of ASP.NET MVC's routing rules.
My intention is to create an action method and URL structure like this:
http://mysite/Animals/Dogs/ViewDog/Buster
DogsController.ViewDog() looks like this:
public ActionResult ViewDog(string dogName)
{
if (dogName!= null)
{
var someDog = new DogFormViewModel(dogName); //snip a bunch more
return View(someDog);
}
else { return View("DogNotFound"); }
}
The task at hand is ensuring that the RegisterRoutes() has the correct entries.
UPDATE
Here's the new route being mapped:
routes.MapRoute("ViewDog", "Animals/{controller}/{action}/{dogName}",
new { controller = "Dogs",
action = "ViewDog", dogName = "" });
The link to the URL is created:
<%= Html.RouteLink("Brown Buster", "ViewDog", new RouteValueDictionary(new { controller="Dogs", action="ViewDog", dogName="Buster" }))%>
The URL is created as expected. Thanks to Craig Stuntz and his blog post on Html.RouteLink.
http://mySite/Animals/Dogs/ViewDog/Buster
New Problem: The param dogName doesn't pickup the string value "Buster" from the URL. The call to the method succeeds, but the argument evaluates to null.
Questions
How can you:
make this route work with a string, and remove the default convention int id in the route? I'd like to change the name of the parameter away from int.
Are you sure that ActionLink is actually matching the route you show them the question? When you have more than one route, I strongly recommend using RouteLink instead of ActionLink, as I explain in great detail in this post. When you use RouteLink, there is no possibility that you will match the wrong route, at least in URL generation.
The default parameter "id" doesn't have to be an int. It'll match whatever type you declare in your action method. Why not just do the following?
public ActionResult ViewDog(string id)
{
if (id!= null)
{
var someDog = new DogFormViewModel(id); //snip a bunch more
return View(someDog);
}
else { return View("DogNotFound"); }
}

Resources