ASP.NET MVC Routing using ID or action name - c#

I have an ASP.Net application which has an area called 'Customers'. This area has a controller with the same name with a single method called Index.
I have the following route defined:
context.MapRoute(null,
"Customers/{controller}/{action}",
new { controller = "customers", action = "Index" }
);
This allows my to navigate to use the following URL to navigate to the index method on my Customers controller.
MyDomain/Customers
In my customer area I also have another controller called products. This has a number of methods that allow me to work with product entities (mostly auto-generated by Visual Studio at the moment).
With my current route I can navigate to the products controller using URL's like this:
MyDomain/Customers/Products (shows the index page of the products
controller) MyDomain/Customers/Products/Create (Shows a page to add
new products). MyDomain/Customers/Products/Details?id=1234 (Show the
product with the id of 1234)
Now what I want to be able to do is navigate to the details page with a much more user friendly URL such as:
MyDomain/Customers/Products/1234
I have defined a new route that look like this:
context.MapRoute(null,
"Customers/Products/{id}",
new { controller = "Products", action = "Details" }
);
The route is defined before the first route I demonstrated.
This allows me to navigate to the products page as I want, however I can no longer navigate to other methods on my products controller.
E.G. The following URL
MyDomain/Customers/Products/Create
Gives me the following error:
The parameters dictionary contains a null entry for parameter 'id' of
non-nullable type 'System.Int32' for method 'System.Web.Mvc.ViewResult
Details(Int32)'
If I change the order of the routes then I can navigate to all the methods on my products controller but my details URL reverts to the old format of having a query parameter.
If I update the route to look like this:
context.MapRoute(null,
"Customers/Products/{id}",
new { controller = "Products", action = "Details", id = UrlParameter.Optional }
);
Then I still get the same problem.
Can anyone tell me how to structure my routes to get the result I want? In summary:
If I navigate to the Customers area I want my URL to look like 'MyDomain/Customers'
If I navigate to the product details page I want my URL to look like "MyDomain/Customers/Products/1234".
If I navigate to any other product page I want my URL to look like 'MyDomain/Customers/Products/Create'

If the ID is always going to be an int then you can add a constraint to the route like this:
context.MapRoute(null,
"Customers/Products/{id}",
new {controller = "Products", action = "Details", id = UrlParameter.Optional},
new {id = #"\d+"} // Constraint to only allow numbers
);

Try something like this:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Products_Details",
"Customers/Products/{id}",
new { controller="Products", action="Details" },
new { id = #"\d+" }
);
context.MapRoute(
"Customers_default",
"Customers/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
Update: added constraint on route.
Explanation: The first route maps to your details page and forces the user to provide an id that has the format of numbers (the last parameter in the first MapRoute). If the id doesn't have the format \d+ it will not match the route and the default will be used. This will give you the following routes:
Customers\Products (index)
Customers\Products\1234 (details of 1234)
Customers\Products\Create (create page for products)
Customers\Products\Edit\1234 (edit page for 1234)

try this
context.MapRoute(
"Customers_Products",
"Customers/Products/{productId}",
new { controller = "Products", action = "Details", productId= UrlParameter.Optional }
);
context.MapRoute(null,
"Customers/{controller}/{action}",
new { controller = "customers", action = "Index" }
);

If you want to keep your existing routes, try doing this:
context.MapRoute(null,
"Customers/Products/{id}", // id is optional, so Customers/Products might reasonably return all products
new { controller = "Products", action = "Details", id = UrlParameter.Optional },
new {id = #"\d+"} // must be numeric if present
);
context.MapRoute(null,
"Customers/Products/{action}/{id}", // Id is optional, so this needs an action.
new { controller = "Products", action = "Details", id = UrlParameter.Optional }
// maybe the id is not numeric for all actions? I don't know so I won't constrain it.
);
context.MapRoute(null,
"Customers/{controller}/{action}", // Default Customers route
new { controller = "customers", action = "Index" }
);
The first two deal with a URL like /Customers/Products/... with one or two other parts and the last one deals with anything else starting with /Customers/

Related

The C# MVC 3 Routing want to add hard code word also in url

The C# MVC 3 Routing i have a controller name Category.
There are 2 Sub Method of the Controller
1)Index
2)Detail
now my detail routing URl coming like this "Category/name" ok but i also want to Add "category/Name-for-all" hard code "-for-all"
want to add this hard code how ?
routes.MapRoute(
"categorie", // Route name
"Category/{id}/{no}", // URL with parameters
new { controller = "Category", action = "details", id = "id",no=UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"categories", // Route name
"Category/{id}/{action}", // URL with parameters
new { controller = "Category", action = "action", id = "id" } // Parameter defaults
);
html page
<div class="grid_3" >
<a class="companyanchor" href="/category/#Model.name/">#Model.Name</a>
</div>
Its hard to understand your question, as I understand you asking about hard coded part of url? Something like this:
routes.MapRoute(null,
"{category}/Page{page}", // Matches /Football/Page567
new { controller = "Product", action = "List" }, // Defaults
new { page = #"\d+" } // Constraints: page must be numerical
);
I have not worked with MVC recently, but isn't this the answer?
routes.MapRoute("categories", // Route name
"Category/{id}"-for-all/{action}", // URL with parameters
new { controller = "Category", action = "action", id = "id" } // Parameter defaults
);
... not sure where "Name" comes from in your example.

RouteUrl + RouteLink while keeping current query string values

In ASP.net MVC I am using Url.RouteUrl & Html.RouteLink to create some links in my page.
Considering the following default route:
routes.MapRoute(
null,
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Using Url.RouteUrl(new { controller = "Products", action = "List", sort = "newest" }) will produce the URL /Products/List?sort=newest.
So far this is exactly what I want. What I'm not sure how to accomplish is the following. If I am currently on /Products/List?sort=newest. and I need to provide the user with a URL to change the number of products listed per page:
`/Products/List?sort=newest&pagesize=30`
How can I use Url.RouteUrl to generate the following URL so that:
If I am currently on a page that has sort=newest, it retains this value: /Products/List?sort=newest&pagesize=30
If I am currently on a page that doesn't have sort, it omits it: /Products/List?pagesize=30
For an example of what I mean, you can look at stackoverflow. If I look at questions and change to view featured questions, and then click on the page size at the bottom it will retain the sorting but then append the page size to the URL.
Url.RouteUrl(
new {
controller = "Products",
action = "List",
sort = Request["sort"],
pagesize = "30"
}
)
If this is invoked from /Products/List it will produce /Products/List?pagesize=30. And if it is invoked from /Products/List?sort=newest it will produce /Products/List?sort=newest&pagesize=30.

Why is the wrong route being used?

I am trying to do what SO does for its Question controller.
/Posts/{id}/{title} when viewing a post (action name not shown)
/Posts/New when you are posting something new.
/Posts/Delete/10 etc....
I have two routes set up (well, one if you don't count the default). What appears to be happening is all actions in the Post controller are being routed through the first one.
What is that? I obviously have it wrong, but I can't figure this out.
routes.MapRoute("ViewPosts",
"Posts/{postid}/{title}",
new { controller = "Posts", action = "View", postid = "", title = "" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
The first route handles all your requests which starts from /Posts.
You need to use constraints to allow {postid} be only number:
routes.MapRoute("ViewPosts",
"Posts/{postid}/{title}",
new { controller = "Posts", action = "View", postid = "", title = "" },
new { postid= #"\d+" });
In this case only if numeric Id is provided this route will handle it, otherwise "Default" route will handle.
All routes are going through the first because you have not specified that the postid field can only be numeric, or defined an earlier route that will catch /Posts/New. It is passing New as the postid with the View action.
You can add this route definition before the ones you have now:
routes.MapRoute("NewPost",
"Posts/New",
new{controller="Posts", action="New"});
Or whatever the appropriate controller/action would be.

Can't bind to parameter

I've got the default routing:
routes.MapRoute(
"Shortie", // Route name
"{controller}/{id}", // URL with parameters
new { controller = "Ettan", action = "Index", id = "id" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Ettan", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I've got a controller: NewsController. It has one method, like this:
public ActionResult Index(int id)
{
...
}
If I browse to /News/Index/123, it works. /News/123 works. However, /News/Index?id=123 does not (it can't find any method named "index" where id is allowed to be null). So I seem to be lacking some understanding on how the routing and modelbinder works together.
The reason for asking is that I want to have a dropdown with different news sources, with parameter "id". So I can select one news source (for instance "sport", id = 123) and it should be routed to my index method. But I can't seem to get that to work.
The ASP.NET MVC Routing works using reflection. It will look inside the controller for a method matching the pattern you are defining in your routes. If it can't find one...well you've seen what happens.
So the answer is (as posted in the comments) to change the type of your id parameter to a Nullable<int> i.e. int?.

Route to controller

I have a controller called Admin with a number of Actions. In the URL, they look like this:
http://www.website.com/Admin/Users/1
http://www.website.com/Admin/Roles/123
Is there anyway to alias out so that:
http://www.website.com/Users/1
http://www.website.com/Roles/123
Automatically goes to the right controller?
Regards.
Not without interfering with the default route, unless you are not going to use the names Users or Roles anywhere else. If that is the case, you can just add
routes.MapRoute(
"AdminUsers",
"Users/{id}",
new { controller = "Admin", action = "Users", id = "" });
routes.MapRoute(
"AdminRoles",
"Roles/{id}",
new { controller = "Admin", action = "Roles", id = "" });
to your Global.asax.cs file.

Categories