ASP.NET routes not triggering as I expect - asp.net

trying to get started with ASP.NET MVC.
I encountered a few difficulties while setting up basic routes.
My routes are as follows:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "ImproItem",
url: "{controller}/{action}/{type}",
defaults: new { controller = "ImproItemForm", action = "Index", type = UrlParameter.Optional }
);
}
My view calls :
<li>#Html.ActionLink("linkLabel", "Index", "ImproItemForm", new { type = "blablabla" }, null)</li>
My controller action sig is:
public class ImproItemFormController : Controller
{
...
public ActionResult Index(String t)
{
...}
}
The view generates the following HTML:
<li>linkLabel</li>
This looks OK to me.
However, this link correctly calls the controller's action (using ImproItem route) but it does not pass the blablabla argument. The parameter t = null when I debug the app.
Can you explain me why?
What should I change to correctly receive the blablabla argument?
Now if I start the application and try to browse
Also is it normal that when I browse:
http://localhost:55193/ImproItemForm/Index?id=foobar
It does call the ImproItemFormController.Index(String t) method ?
I did not expect that this URL would match with this route:
routes.MapRoute(
name: "ImproItem",
url: "{controller}/{action}/{type}",
defaults: new { controller = "ImproItemForm", action = "Index", type = UrlParameter.Optional }
);
I thought the argument needs to have the same name than in the route : type and not id.
Thx in advance for your help.

I thought the argument needs to have the same name than in the route :
type and not id.
Actually when you request the URL - http://localhost:55193/ImproItemForm/Index?id=foobar, it actually calls the Default route only, and not the custom route that you have created. Default route has - controller name, action name and id. That means, if there is any URL matching this pattern (i.e., {controllername}/{actionname}/{id}) would match the default route.
Order of routes are very important in route collection because route table is built top-to-bottom, so as soon as the URL finds its first matching route, it stops scanning further.So ideally, default route should be the bottom most route in route collection.
I guess all your problems for this particular scenario should be resolved by performing following two steps-
Move default route to the bottom in route collection in RouteConfig.cs
Rename parameter "t" to "type" in Index action.

Change the name of the parameter in your action to match the name in the ActionLink
public ActionResult Index(String type)

Related

How does RedirectToRoute work and how to pass data in it?

I'm trying to redirect to a route that is in the RecomController and the action is Index, i have defined the path in my RouteConfig file and have also specified an id parameter that i pass when i call my RedirectToRoute function. For some reason it can't find that path.
I have also created a Route attribute above the RecomController Index action but it still doesn't navigate me to that path. Am i missing something?
RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Recomroute",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Recom", action = "Index", id = UrlParameter.Optional }
);
}
RecomController.cs:
[Route("Recom/Index")]
public ActionResult Index(int id)
{
............//Functioning
}
Calling the function (IN ANOTHER CONTROLLER):
ProjectController.cs:
return RedirectToRoute("Recom/Index/{id}", new {id = projectdto.Id });
Sounds like you're using wrong route name or path in RedirectToRoute(), hence it doesn't work:
// this is wrong because first parameter did not match
return RedirectToRoute("Recom/Index/{id}", new {id = projectdto.Id });
For two parameters overload, it requires route name (not route path) and route values, as shown in definition below:
protected internal RedirectToRouteResult RedirectToRoute(string routeName,
RouteValueDictionary routeValues)
Hence, you need to provide complete route name and route values defined in RegisterRoutes (e.g. Recomroute).
return RedirectToRoute("Recomroute", new {
controller = "Recom",
action = "Index",
id = projectdto.Id
});
Side notes:
1) You still need to provide controller, action and id parameters in order to match route definition.
2) The Recomroute seem defined below default route with same route segments definition which overrides all custom routes beneath it, if you want to evaluate Recomroute first move it to the top order and use different path against default route.

No controller specified in route

Situation:
I have a ASP.NET application where I have different controllers. I changed in the RouteConfig the route to:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"SpecificRoute",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Error", action = "NotFound", id = UrlParameter.Optional }
All pages in my the HomeController are working fine. One way I go to them is with a ActionLink:
#Html.ActionLink("Index Page", "Index", "Home")
And that works fine, even as other ways with the context as: "example", "Home".
It goes wrong when I select an other controller, let's say:
#Html.ActionLink("GoToErrorPage", "NotFound", "Error") // error page
The result of this link is that it just connects to the home page. It does not go the the correct page.
I want to connect to all pages (in other controller's too) with a URL like:
http://localhost:12345/Request
How the original url looked like (before the change in the RouteConfig)
http://localhost:12345/Home/Request
Question:
How do I need to configure the RouteConfig?
How do I set it that I don't need to type the controller before the
action in the url?
How do I set the ActionLink correct?
Both your routes are effectively the same in that they both match any url with 2 segments. If you want to be able to navigate to a method without specifying the controller name, then you will need to create specific routes for each of those methods. For example if you want to navigate to the Request(int? id) method of HomeController, with ../Request or ../Request/1 then you need
routes.MapRoute(
"Request",
"Request/{id}",
new { controller = "Home", action = "Request", id = UrlParameter.Optional }
);
and that route must be placed before the default route
Then in the view #Html.ActionLink("Request Page", "Request", "Home") will generate a url of ../Request and go the the Request() method of HomeController

Routing url with several params

I'm trying to build a REST API with ASP mvc and i'm having some trouble with the routing.
I would like to match the following urls in a nice and convenient way:
https://foo.com/collections/
https://foo.com/collections.json/
https://foo.com/collections.xml/
https://foo.com/collections/collectionID/
https://foo.com/collections/collectionID.json/
https://foo.com/collections/collectionID.xml/
And in future more items on the same pattern:
https://foo.com/persons/
https://foo.com/persons.json/
https://foo.com/persons.xml/
https://foo.com/persons/personID/
https://foo.com/persons/personID.json/
https://foo.com/persons/personID.xml/
My best attempt so far is:
routes.MapRoute(
name: "RESTCollections",
url: "{controller}s/",
defaults: new { controller = "Collection", action = "Index" }
);
routes.MapRoute(
name: "RESTCollections",
url: "{controller}s/{format}/",
defaults: new { controller="Collection", action="Index", format = UrlParameter.Optional },
constraints: new { format = "json|xml|html" }
);
It manages to match:
https://foo.com/collections/
https://foo.com/collections/json
But I'm stuck there trying to replace the "/" between the controller and format gives 404. Simply removing the "/" also gives 404.
To answer your question you could try
`context.MapRoute(
"Api_default",
"{controller}/{action}.{format}",
new { controller = "Home", action = "Index", format = UrlParameter.Optional });`
As stated here stackoverflow.com/.../customizing-asp-net-mvc-routing-to-service-json-xml-style-urls
On the other hand I don't see why you would like to state which format you want to accept to be sent to your API.
You could use the [FromBody] string content which deserialises the sent value to the method.
Or you could define the type of the parameter with the Route attribute
[Route("Post/{collection:string}")
public void Post(string collection)
Where string is a predefined constraint, you can create your own custom constraints.

RedirectToAction() generates wrong URL

I'm having a problem with MVC 4, and I guess it's something really trivial, but it's been bugging me for the last day and I can't seem to figure it out.
I have this url:
http://www.example.com/my-dashed-url
I have a Controller named:
public class MyDashedUrlController: Controller
{
}
I have only two Routes like this:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("my-dashed-url",
"my-dashed-url/{action}",
new { controller = "MyDashedUrl", action = "Index" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional }
);
I get to the index just fine. However, when I do this:
public ActionResult Index()
{
if (NoUserIsLoggedOn)
return RedirectToAction("Logon", "MyDashedUrl");
return View();
}
public ActionResult Logon()
{
Contact c = GetContact();
return View(c);
}
It doesn't redirect me to the "Logon" action properly.
It should redirect me to:
http://www.example.com/my-dashed-url/logon
but instead it tries to redirect me to:
http://www.example.com/logon
... which doesn't work (404 Not Found)
I'm missing something. Can anyone spot it? If anyone needs any more information, let me know.
And it's EVERY RedirectToAction that does the same thing in this controller. A Html.BeginForm("Logon", "MyDashedUrl") would also generate:
http://www.example.com/logon
I guess it has to do something with the Routes I defined, but I can't find the faulty one, seeing as they're all the same. If I disable all of my Routes besides the default one from MVC, the problem remains the same
Make sure that you have declared this custom route BEFORE the default one:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"my-dashed-url",
"my-dashed-url/{action}",
new { controller = "MyDashedUrl", action = "Index" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Remember that routes are evaluated in the order you declared them. So the first route that matches a request will be used. If you declare your custom route after the default one, it is the default route that will match the request.

Switching to {controller}/{id}/{action} breaks RedirectToAction

I am trying to use proper REST urls with MVC. To do that I switched default Routing from:
{controller}/{action}/{id}
to
{controller}/{id}/{action}
so instead of:
/Customer/Approve/23
there is now
/Customer/23/Approve
ActionLink seems to work ok, but the following code in CustomerController:
[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
_customerService.Approve(id);
return RedirectToAction("Search"); //Goes to bad url
}
ends up on url /Customer/23/Search. While it should be going to /Customer/Search. Somehow it remembers 23 (id).
Here is my routing code in global.cs
routes.MapRoute(
"AdminRoute", // Route name
"{controller}/{id}/{action}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { id = new IsIntegerConstraint() }
);
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" });
If I switch the two functions, RedirectToAction starts working, but using:
Html.ActionLink("Approve", "Approve", new { Id = 23})
Now generates /Customer/Approve?id=23, instead of /Customer/23/Approve.
I could specify direct urls like ~/Customer/23/Approve, instead of using ActionLink and RedirectToAction, but would rather stick to functions provided by MVC.
When you use RedirectToAction(), internally, MVC will take the existing route data (including the Id value) to build the url. Even if you pass a null RouteValueDictionary, the existing route data will be merged with the new empty route value data.
The only way around this I can see is to use RedirectToRoute(), as follows:
return RedirectToRoute("Default", new { controller = "Customer", action = "Search"});
counsellorben
Try passing in new (empty) RouteValueDictionary in your controller
return RedirectToAction("Search", new System.Web.Routing.RouteValueDictionary{});
And here:
Html.ActionLink("Approve", "Approve", new { Id = 23})
I don't even know how can it pick up the Customer controller, since you are not specifying it anywhere. Try providing both controller and action to ActionLink helper.
Try passing the current route data to methon in your controller action:
return RedirectToAction("Search", this.RouteData.Values);
Remove this part:
id = UrlParameter.Optional
may be resolve the problem; when you define "id" as an optional parameter, and you have the "Default" map, the "Default" and the "AdminRoute" are same together!
regards.
I was having a similar problem. Route values that were passed to my controller action were being reused when I tried to redirect the user with RedirectToAction, even if I didn't specify them in the new RouteValueDictionary. The solution that I came up with (after reading
counsellorben's post) with was to clear out the RouteData for the current request. That way, I could stop MVC from merging route values that I didn't specify.
So, in your situation maybe you could do something like this:
[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
_customerService.Approve(id);
this.RouteData.Values.Clear(); //clear out current route values
return RedirectToAction("Search"); //Goes to bad url
}
I had a similar problem and was able to solve it by adding the id to the default route as well.
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
If there is truly no id in your default route then you could also try:
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index", id = string.Empty });

Resources