ASP.NET MVC URL routing doesn't give me pretty URLs - asp.net-mvc

I have set up an ASP.NET MVC project, and everything is working great, but I do have one problem with the routing. My Global.asax looks like this:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
So, nothing out of the ordinary. My problem is that when I link to a controller/action/params with an HTML.ActionLink like so:
<%= Html.ActionLink("My link", "SomeAction", "SomeController", new {param="someParam"})%>
it should generate (at least what makes sense in my head) a link such as: http://www.localhost/SomeController/SomeAction/someParam.
But instead it generates a link like this: http://localhost/SomeController/SomeAction?param=someParam
If i manually make a link that links to the expected result (SomeController/SomeAction/someParam) then the right controller and action are called, but the parameter defined in the action method is always null.
Any ideas?

try adding:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{param}", // URL with parameters
new { controller = "Home", action = "Index", param = "" } // Parameter defaults
);

I think that link will only use the default route like you expect if the parameter name is id instead of param. You'll have to create a different route if you want to provide some other parameter there.

Related

I am using routing in MVC. But when i am using other url same as route url it is redirecting to the same action

routes.MapRoute(
"GetProductBySubcategory", // Route name
"{category}/{SubCategoryName}", // URL with parameters
new { controller = "Product", action = "GetProductBySubCategoryName"
});
Here is my route that is working fine.
But when is am using the url Like localhost:12345/Admin/Login then it use the route url and redirect to GetProductBySubCategoryName action.
actually i am using #Url.RouteUrl() method to call the route. which is working good. But when other url like Account/Register means which have only two keys redirect to action given in the route.
I am using other routes
All routes that i am using is as follow:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"GetProductByCategory",
"{category}",
new { controller = "Product", action = "GetProductByCategoryName" }
);
routes.MapRoute(
"GetProductBySubcategory",
"{category}/{SubCategoryName}",
new { controller = "Product", action = "GetProductBySubCategoryName" }
);
routes.MapRoute(
"ProductByNameRoute",
"{category}/{subcategory}/{style}/{productName}",
new { controller = "Product", action = "ProductDetails" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
this is my route.config file.
i am not able to call sign in link, login link the all goes to route url.
acctually i want to route url like if i click on getproductbycategory url will domain/category and if i click on getproductbysubcategory url will be domain/category/subcategory.
Please help me to find the solution.
If you are working on MVC 5 you can easily achieve this by attribute routing, without modifying the route table.
Attribute Routing in MVC 5

asp.net mvc basic routing issue

i have two folder under view folder. one is Home and that has index.aspx file
another folder in view folder called DashBoard and that has MyDash.aspx
my routing code look like in global.asax
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"DashBoard", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "DashBoard", action = "MyDash", id = UrlParameter.Optional } // Parameter defaults
);
}
so when i type url like http://localhost:7221/ or http://localhost:7221/Home then index.aspx is being render from Home folder but when i type url like http://localhost:7221/DashBoard then page not found is coming but if i type like http://localhost:7221/DashBoard/MyDash then page is coming.
so what is wrong in my second routing code . why MyDash.aspx is not coming when i type url like http://localhost:7221/DashBoard. what is wrong?
what i need to change in my second routing code??
please have a look.....i am new in MVC. thanks
My UPDATE
when i change route entry in global.asax file then it started working.
can u please explain why....
routes.MapRoute(
"DashBoard",
"DashBoard/{action}/{id}",
new { controller = "DashBoard", action = "MyDash", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
can i write routing code this way
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { controller = "DashBoard", action = "MyDash", id = UrlParameter.Optional }
);
same pattern for two url....please discuss in detail. thanks
The route names (1st parameter) have no impact on what action/controller gets invoked.
Your 2 route patterns, however, (2nd paramters of routes.MapRoute) are identical :
"{controller}/{action}/{id}"
... so anything that would be matched by the 2nd pattern gets caught by the first pattern. Therefore they're all getting mapped by the first map definition.
http://localhost:7221/Home works because it matches the first pattern, and presumably, the Index action exists inside your Home controller.
http://localhost:7221/DashBoard/MyDash works because, even though it's getting matched by the 1st route, it overrides the default action/controller (Home/Index) by the route parameters passed in through the URL (DashBoard/MyDash).
http://localhost:7221/DashBoard doesn't work because it's getting picked up by the first route pattern, but you didn't pass in an action name, so it looks for the default -- Index -- which I'm guessing you haven't set up within the DashBoard controller.
UPDATE (how to fix the problem):
So if you want http://localhost:7221/DashBoard to map to Controller named DashBoard with an action named MyDash, while still allowing other patterns to be picked up by {controller}/{action}/{id} delete your 2nd route, and place this one as the 1st route:
routes.MapRoute(
"DashBoard",
"DashBoard/{action}/{id}",
new { controller = "DashBoard", action = "MyDash", id = UrlParameter.Optional }
);
This is a more specific route, so it needs to go before the catch-all {controller}/{action}/{id}. Nothing that doesn't start with /DashBoard will get picked up by it.

ASP.NET MVC + WebForms - route conflict

I'm building a simple report Web app for rendering reports using ASP.NET MVC3 + WebForms. The reports themselves are rendered by the ReportViewer ASP.NET WebForms control, but I'd like use ASP.NET MVC to create the parameter entry.
I'd like to have that all requests follow the default routing scheme of '~/{controller}/{action}/{parameters}', except requests for ~/Report, which should go to the report rendering WebForm. What's the right way to do this?
Expanding a bit..
I have two routes in Global.asax.cs - the default one and one for the WebForms page.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapPageRoute("report-rendering", "Report", "~/Render.aspx");
}
The URLs get rendered fine, but the problem with this is that when the request comes in, the first route also eats the URLs for the second one, i.e. ~/Report?id=7 tries to call the Index method on the ReportController (which doesn't exist).
If I change it so that the 'report-rendering' route comes before the 'Default' route, like so:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapPageRoute("report-rendering", "Report", "~/Render.aspx");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Now calls to the Html.ActionLink() render incorrect URLs, i.e.
`#Html.ActionLink("Report list", "Index", "ReportList")`
Renders
`http://localhost:49910/Report?action=Index&controller=ReportList`
My current workaround puts the 'Default' route first, while adding a regex constraint to ignore requests for the 'Report' controller, like so:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { controller = #"(?!report$).*" }
);
This doesn't feel clean. Again, What's the right way of doing this?
Also, I haven't yet decided how I'll pass the parameters to the rendering form: I could use both query parameters or POST them. I'm guessing that query params are more flexible. What's the best practice here?
EDIT:
While researching the answer by #LeftyX, seems like I've found an answer. To quote P. Haack from his Routing chapter in the Professional ASP.NET MVC 3 (Named Routes, Chapter 9, page 233):
... Use names for all your routes and
always use the route name when generating URLs. Most of the time, letting Routing sort out which
route you want to use to generate a URL is really leaving it to chance, which is not something that
sits well with the obsessive-compulsive control freak developer. When generating a URL, you generally
know exactly which route you want to link to, so you might as well specify it by name.
The mentioned section discusses a very similar situation to the one I described.
But since Html.ActionLink() doesn't have an overload with the route name parameter, does this mean I cannot reliably use it anywhere in the entire app if have a route like this?
This is the best solution I've figured out.
I've registered my route with MapPageRoute (I've put my Report page under a folder called Reports)
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapPageRoute(
"report-rendering",
"Report/{id}",
"~/Reports/Report.aspx"
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I've created my link using RouteLink so you can specify the route to use:
#Html.RouteLink("Report list", "report-rendering", new { id = 7 })
and I can get the id in my WebForm page like this:
protected void Page_Load(object sender, EventArgs e)
{
var id = Page.RouteData.Values["id"] as string;
}
Hope it helps.
UPDATE:
I've created an Extension Method to make your life easier:
public static class ExtensionMethods
{
public static MvcHtmlString WebFormActionLink(this HtmlHelper htmlHelper, string linkText, string ruoteName, object routeValues)
{
var helper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var anchor = new TagBuilder("a");
anchor.Attributes["href"] = helper.RouteUrl(routeName, routeValues);
anchor.SetInnerText(linkText);
return MvcHtmlString.Create(anchor.ToString());
}
}
The best would have been to use ActionLink instead of WebFormActionLink but I have problems with signatures and I am not an expert on this.

Routing in MVC not working

I have the following route:
routes.MapRoute(
"Property",
"{language}/property/{propertyUrlId}",
new { controller = "PropertyDetails", action = "Property" }
This is the Controller that should be called for that route:
public class PropertyDetailsController : Controller
{
public ActionResult Property(string language, string propertyUrlId)
{
etc.
And the following URL that should use that route:
http://domain.com/en-us/property/3
Instead, I get 404. Any ideas why?
Here are my routes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
"Property",
"property/{propertyUrlId}",
//new { controller = "PropertyDetails", action = "Property" }, new { language = #"[a-zA-Z]{2}-[a-zA-Z]{2}" }
new { controller = "PropertyDetails", action = "Property" }
);
}
Didn't work with language, or with language/country, either.
You most likely have registered the default route before your Property route. Default route typically looks like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Just register your Property route BEFORE this default route and it will work.
Why it fails? (Assuming you are indeed registering default route first)
en-us -> is interpreted as controller
property -> is interpreted as action
Since you don't have a en-usController with a Property action -> 404
Use "en-us" as a segment of the URL is completely fine. I guess you have registered other routes as well. Try to bring this route to the top of others and at least on top of the default route.
I have tested the scenario, it works just fine for me.
Considering that you want to have the structure of the url as:
http://domain.com/en-us/property/3
use this routing:
routes.MapRoute(
"Property", // Route name
"{language}/property/{propertyUrlId}", // URL with parameters
new { controller = "PropertyDetails", action = "Property", propertyUrlId = UrlParameter.Optional } // Parameter defaults
);
if there is a default routing in your Global.asax file, like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Put the routint above this block of code.
And your Controller Action should look like this:
public ActionResult Property(int propertyUrlId)
{
return View();
}
First of all, there is no reason to break {language} apart into two chunks in the route. As some of you stated, this is fine:
routes.MapRoute(
"Property",
"{language}/property/{propertyUrlId}",
new { controller = "PropertyDetails", action = "Property" }
Second, I omitted some information which was crucial to the solving of this problem. It didn't occur to me to include this in my problem description, as I didn't know there was any relationship. The MVC project is in a solution which also contains a website (non-MVC) which is using the Sitecore CMS as its datastore. Sitecore was stripping out the language segment of the URL and storing it, itself. Once I learned that this was happening, I was able to deal with the problem.
I appreciate all the input, and I apologize for the confusion.

RedirectToAction - but I want it to go to http://example.com/controller/action/id?

I'd like to move an asp.net mvc response to
http://example.com/emails/list/rob#email.com
Using RedirectToAction("list", "emails", new { id = "rob#email.com"}); takes you to http://example.com/emails/list?id=rob#email.com.
What am I doing wrong?
Thanks,
Rob
Seems like misconfigured routing. Your RegisterRoutes method in Global.asax.cs should look like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Account", action = "Login", id = "" } // Parameter defaults
);
}
In line "{controller}/{action}/{id}" presence of {id} means that is going to be substituted by it's value.
Any other parameter that is not present in routing string would be decoded as ?some_param=value
Ah - because the default route requires 'id', your parameters in the view (html) and the controller must be called id.

Resources