I am altering an ASP.NET, MVC, C# application but a routes.MapRoute entry isn't working as expected. In my Global.asax.cs file I have the following two routes -
routes.MapRoute(
"MyRoute1", // Route name
"{controller}/{action}/{something}/{name}/{id}/{myParameterA}",
new { controller = "MyController", action = "MyActionA", category = "something", name = "name", id = "id", myParameterA = "myParameterA" });
routes.MapRoute(
"MyRoute2", // Route name
"{controller}/{action}/{something}/{name}/{id}/{myParameterB}",
new { controller = "MyController", action = "MyActionB", category = "something", name = "name", id = "id", myParameterB = UrlParameter.Optional } );
The code in my controller looks like this -
public ActionResult MyActionA(string something, string name, string id, string myParameterA)
{
//do cool stuff!
}
public ActionResult MyActionB(string something, string name, string id, string myParameterB)
{
//do awesome stuff!
}
When I call MyActionB, the final parameter myParameterB is coming into the Controller as null even when the parameter is in the URL - (example: /MyController/MyActionB/aThing/aName/123/456).
I do want the final parameter ('456' in my above example) to be optional.
MyActionA is working fine.
Any suggestions would be appreciated!
Also, is there a good reference out there on how routes.MapRoute works?
Thank you!
This is because there is nothing to distinguish between those 2 routes once you replace the parameters with strings in the route itself. If you add a static part to the routes you should be able to differentiate between them.
routes.MapRoute(
"MyRoute1", // Route name
"{controller}/{action}/{something}/{name}/{id}/firstroute/{myParameterA}",
new { controller = "MyController", action = "MyActionA", category = "something", name = "name", id = "id", myParameterA = "myParameterA" });
routes.MapRoute(
"MyRoute2", // Route name
"{controller}/{action}/{something}/{name}/{id}/secondroute/{myParameterB}",
new { controller = "MyController", action = "MyActionB", category = "something", name = "name", id = "id", myParameterB = UrlParameter.Optional } );
See if that works.
Not sure but I think swap the two around, when you set "myParameterA = "myParameterA"" on the first, you're assigning a default value, when you pass /MyController/MyActionB/aThing/aName/123/456 the url is mapped to the first, but the number 456 is not compatible with the default string value - and so is passed as null.
EDIT: oh and for a good reference, the Apress Pro MVC 3 has an excellent chapter on this - Safari Informit.
Related
I've been working on a large MVC application over the past month or so, but this is the first time I've ever needed to define a custom route handler, and I'm running into some problems. Basically I have two parameters to pass. The first one is required and the second one is optional.
I'm following this answer here.
Here is my custom route:
routes.MapRoute(
"MyRoute",
"{controller}/{action}/{param1}/{param2}",
new {
controller = "MyController",
action = "MyAction",
param1 = "",
param2 = "" // I have also tried "UrlParameter.Optional" here.
}
);
And my action method signature:
public ActionResult MyAction(string param1, string param2)
If I try the URL http://[myserver]/MyController/MyAction/Test1/Test2 then it works like I expect it to, with param1 = "Test1" and param2 = "Test2"
If I try the URL http://[myserver]/MyController/MyAction/Test1 then both parameters are null.
Hopefully somebody can tell me what I'm doing wrong here, because I'm lost.
I assume that you created new route and left the default one that is very similar to yours. You should be aware that collection of routes is traversed to find first matching route. So if you have left the default one:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
above your route then it will match request to http://[myserver]/My/MyAction/Test1 and call MyController.MyAction and set "Text1" to parameter named id. Which will fail because this action is not declaring one named id.
What you need to do is to move your route as first in routes list and make it more specific then it is now:
routes.MapRoute(
"Route",
"My/{action}/{param1}/{param2}",
new
{
controller = "My",
action = "MyAction",
param1 = "",
param2 = ""
});
This will force all traffic routed trough My to match this route.
hi you create your rout like this i think this will hep you
routes.MapRoute(
"Regis", // Route nameRegister
"Artical/{id}", // URL with parameters
new { controller = "Artical", action = "Show", id = UrlParameter.Optional } // Parameter defaults
);
Try this
routes.MapRoute("MyRoute",
"myRoute/{param1 }/{param2 }",
new { controller = "MyController", action = "MyAction", param2 = UrlParameter.Optional },
new { param2 = #"\w+" });
you can specify one parameter as optional by using "UrlParameter.Optional" and specified second one with DataType means if you pass integer value then DataType (#"\d+") and for string i have mention above.
NOTE: Sequence of parameter is very important Optional parameter must pass at last and register your new route Before Default Route In Gloab.asax.
then you action link like
Test
OR with one parameter
Test
In you Controller
public ActionResult MyAction(string param2,string param1)
{
return View()
}
I have a controller named Raportare that has two actions: ReportA and ReportB.
Both return an excel file based on the parameters supplied.
public ActionResult ReportA(int? month, int? year)
{
...
}
public ActionResult ReportB(int? month, int? year)
{
...
}
My global.asax has the following routing rules for this :
routes.MapRoute(
"ReportA",
"{Raportare}/{ReportA}/{month}/{year}",
new { controller = "Raportare", action = "ReportA", month = UrlParameter.Optional, year = UrlParameter.Optional});
routes.MapRoute(
"ReportB",
"{Raportare}/{ReportB}/{month}/{year}",
new { controller = "Raportare", action = "ReportB", month = UrlParameter.Optional, year = UrlParameter.Optional });
However when I go mysite.com/Raportare/ReportB/5/2012 it's returning the ReportA file.
It works fine if I go to mysite.com/Raportare/ReportB?month=5&year=2012.
Probably I'm doing something wrong in the routing rules but I can't figure it out.
You don't need to add a route for every action - they work like templates and the 3rd parameter is just default values.
routes.MapRoute(
"reports",
"Raportare/{action}/{month}/{year}",
new {
controller = "Raportare",
action = "ReportA",
month = UrlParameter.Optional,
year = UrlParameter.Optional
}
);
Put this before your default rule in Global.asax.cs, otherwise the default might match first.
Then mysite.com/Raportare/ReportB/5/2012 will invoke the ReportB action because it has been specified in the url.
mysite.com/Raportare will invoke ReportA, because it is the default action.
The routes you've created are basically the same. That's why the first one which matches request string succeeds and first action gets invoked.
Here I have:
routes.MapRoute(
"test", // Route name
"DataWarehouse/Distribution/{category}/{serialNo}",
new { controller = "DataWarehouse",
action = "Distribution",
category= UrlParameter.Optional,
serialNo = UrlParameter.Optional }
);
Category and serialNo are both optional params. When the routing is like: DataWarehouse/Distribution/123, it always treat 123 as the value for category.
My question is how I can make it to know the 1st param could be either category or serialNo, i.e. DataWarehouse/Distribution/{category} and DataWarehouse/Distribution/{serialNo}.
DataWarehouse/Distribution/{category}/{serialNo}
Only the last parameter can be optional. In this example category cannot be optional for obvious reasons.
If you know what your parameters will look like you can add a route constraint to differentiate both routes
Ex if your serial are 1234-1234-1234 and your category are not like this:
routes.MapRoute(
"serialonly", // Route name
"DataWarehouse/Distribution/{serialNo}",
new { controller = "DataWarehouse",
action = "Distribution",
category= UrlParameter.Optional,
serialNo = UrlParameter.Optional },
new{serialNo = #"\d{4}-\d{4}-\d{4}"}
);
routes.MapRoute(
"test", // Route name
"DataWarehouse/Distribution/{category}/{serialNo}",
new { controller = "DataWarehouse",
action = "Distribution",
category= UrlParameter.Optional,
serialNo = UrlParameter.Optional },
,
new{serialNo = #"\d{4}-\d{4}-\d{4}"}
);
I had a similar problem, i was trying to route based on data ({year}/{month}/{day}) where month or day could be optional. What I found was that I couldn't do it with a single route. So I solved it by using 3 routes, from generic to specific (year, year and month, year and month and day). I am not completely pleased with it, but it works.
So provided that you are looking for DataWarehouse/Distribution/{category} and DataWarehouse/Distribution/{category}/{serialNo} routes, i think this would work for you.
lets say I have a controller named Store. There is an index method:
public ActionResult Index(string val, long? id, int? id2)
{
return View();
}
I want to fetch things like:
/my-store/some-text
/my-store/some-text/
/my-store/some-text/123456789012335
/my-store/some-other-text/4562343462345
/my-store/some-other-bla-text/4562343462345/1
/my-store/some-other-bla-bla-text/45345723554/2
So the requerements are:
+ the controller link-text is "my-store" and has to route to Store controller
+ if there is only some text and id, then just leave id2 null
+ if there is only some text and no id, then just leave id and id2 null
Is the following correct?
routes.MapRoute(
"Store", // Route name
"my-store/{val}/{id}/{id2}", // URL with parameters
new { controller = "Store", action = "Index", id = UrlParameter.Optional, id2 = UrlParameter.Optional }
);
Thank you for your help in advance!
Yeah looks good except you need to define a default value for {val} in your route:
routes.MapRoute(
"Store", // Route name
"my-store/{val}/{id}/{id2}", // URL with parameters
new { controller = "Store", action = "Index", val = "", id = UrlParameter.Optional, id2 = UrlParameter.Optional }
Just remember to cleanse the string in val as if you have some funky characters then your link won't work. Like let's say val equal "thisis/val", then your link will be:
/my-store/thisis/val/1212/12
Which would not hit your route and most likely return a 404
I can't seem to retrieve an ID I'm sending in a html.ActionLink in my controller, here is what I'm trying to do
<li>
<%= Html.ActionLink("Modify Villa", "Modify", "Villa", new { #id = "1" })%></li>
public ActionResult Modify(string ID)
{
ViewData["Title"] =ID;
return View();
}
That's what a tutorial I followed recommended, but it's not working, it's also putting ?Length=5 at the end of the URL!
Here is the route I'm using, it's default
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
Doesn't look like you are using the correct overload of ActionLink. Try this:-
<%=Html.ActionLink("Modify Villa", "Modify", new {id = "1"})%>
This assumes your view is under the /Views/Villa folder. If not then I suspect you need:-
<%=Html.ActionLink("Modify Villa", "Modify", "Villa", new {id = "1"}, null)%>
In MVC 4 you can link from one view to another controller passing the Id or Primary Key via
#Html.ActionLink("Select", "Create", "StudentApplication", new { id=item.PersonId }, null)
Don't put the # before the id
new { id = "1" }
The framework "translate" it in ?Lenght when there is a mismatch in the parameter/route
On MVC 5 is quite similar
#Html.ActionLink("LinkText", "ActionName", new { id = "id" })
The ID will work with # sign in front also, but we have to add one parameter after that. that is null
look like:
#Html.ActionLink("Label Name", "Name_Of_Page_To_Redirect", "Controller", new {#id="Id_Value"}, null)
If the target action requires a parameter, you can use an anonymous object to pass parameter values:
#Html.ActionLink(“View Movies”, “Index”, “Movies”, new{id=1},null)
Where:
-View Movies-->String LinkText
-Index--> string ActionName
-Movies-->string ControllerName
-new{id=1}-->(object) Is the parameter values that you want to pass
-Null-->object htmlAttributes
*For Example:
This should generate a link like the following:
/movies/index/1