MVC4 Route with Id and Index Action - asp.net-mvc-4

I'm trying to accomplish the following and receiving the "resource not found" error for #2. Assuming because the routing is not configured correctly.
Desired URLs:
1) domain.com/Customer
2) domain.com/Customer/1 *Does Not Work
3) domain.com/Customer/All
public ActionResult Index(int? id)
{
var viewModel = new CustomerViewModel();
if (!id.HasValue)
id = 1; // ToDo: Current Logged In Customer Id
viewModel.Load(id.Value);
return View(viewModel);
}
public ActionResult All()
{
return View(CustomerModel.All());
}
My Route Config has the default route setup and I've tried adding an additional route to no avail.
routes.MapRoute(
name: "Customer",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Customer", action = "Index", id = UrlParameter.Optional }
);
I've excluded my attempts at setting up a new route since it doesn't work.

Your route would normalize out to domain.com/Customer/Index/1. When you have subsequent parts of the route, you can't eliminate an earlier component just because its value will be the default. In this case, it's looking for an action named "1" which it can't find.
Edit:
If your desired route is domain.com/Customer/ID, then you can add such a route to your route table:
routes.MapRoute(
name: "CustomerAll",
url: "Customer/All",
defaults: new { controller = "Customer", action = "All" }
);
routes.MapRoute(
name: "CustomerByID",
url: "Customer/{id}",
defaults: new { controller = "Customer", action = "Index" }
);
These more-specific routes should come before your default route.

try to add this route before the default one
routes.MapRoute(
name: "Customer",
url: "Customers/{id}",
defaults: new { controller = "Customer", action = "Index", id = UrlParameter.Optional }
);
and note that the url starts with Customers not Customer.
and your desired URL will be : domain.com/Customers/1 instead of domain.com/Customer/1

Related

ASP.Net Routing: Customer ID not passing to action

see my url localhost:55831/Customers/Edit/1/ALFKI which i generate using #Html.RouteLink
#Html.RouteLink("Edit", "PageWithId",
new
{
controller = "Customers",
action = "Edit",
id = item.CustomerID,
page = ViewBag.CurrentPage
})
here is my routing code for PageWithId i tried two routing one after one but none work
routes.MapRoute(
name: "PageWithId",
url: "{controller}/{action}/{page}/{id}"
);
AND
routes.MapRoute(
name: "CustomerEditWithId",
url: "Customers/Edit/{page}/{id}",
defaults: new { controller = "Customers", action = "Edit" }
);
my all routing code
routes.MapRoute(
name: "PageWithSort",
url: "{controller}/{action}/{page}/{SortColumn}/{CurrentSort}",
defaults: new { action = "Index", page = UrlParameter.Optional, SortColumn = UrlParameter.Optional, CurrentSort = UrlParameter.Optional }
);
routes.MapRoute(
name: "PageWithId",
url: "{controller}/{action}/{page}/{id}"
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
please some one help because when i am clicking ob this link localhost:55831/Customers/Edit/1/ALFKI then customer id ALFKI is not passing to edit action. i debug the edit action code and found id is getting null always. i tried few routing for edit action but no luck still.
The order of routes matters. Routes are checked in order and the first matching route wins.
Because your first (PageWithSort) route matches any route with between 1 and 5 segments, then /Customers/Edit/1/ALFKI, which contains 4 segments matches, and no further routes are checked. And since ALFKI is being passed to the 4th segment named SortColumn, then it will only be bound to a parameter named SortColumn in your Edit() method (not to something named id)
As it stands, your PageWithId and Default routes are pointless since they can never be hit.
In additional, only the last parameter in a route definition can be marked with UrlParameter.Optional.
You need to create specific routes, and locate them in the correct order. Change your route definitions to (note I have omitted the PageWithSort route because its not clear what you want to do with that and it contains errors anyway)
routes.MapRoute(
name: "CustomerEditWithId",
url: "Customers/Edit/{page}/{id}",
defaults: new { controller = "Customers", action = "Edit" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Now any url that begins with /Customers/Edit and contains 2 additional segments will match the CustomerEditWithId route, and the 3rd segment will be bound to a parameter named page and the 4th segment will be bound to a parameter named id. Therefore your method in CustomersController should be
public ActionResult Edit(int page, string id)

MVC Routing News Pages

I have managed to get my MVC project to present a list of news items in an SEO friendly manner:
/News/ - to present the list
/News/NewsItem/id/news-item-title - the individual news item
What I would really like is:
News/id/news-item-title
Exactly how Stackoverflow presents its questions.
However, I cant seem to get my head around how to do the routing to differentiate between two actions with the same controller action name (Index).
Any suggestions would be appreciated.
EDIT:
Here's my routes config:
routes.MapRoute(
"News",
"News/NewsItem/{newsId}/{newsTitle}",
new { controller = "News", action = "NewsItem", newsTitle = UrlParameter.Optional },
new { newsId = #"\d+" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "SkipHire", action = "Index", id = UrlParameter.Optional }
);
EDIT 2:
This is what I've amended everything to:
Route
routes.MapRoute(
"News",
"{controller}/{id}/{newsTitle}",
new { action = "NewsItem", newsTitle = UrlParameter.Optional }
);
Controller
public class NewsController : Controller
{
public ActionResult Index()
{
var q = _ctx.tblNews.OrderBy(x => x.newsCreateDate)
.Where(x => x.WebsiteID == 2).ToList();
return View(q);
}
public ActionResult NewsItem(int newsId, string newsTitle)
{
return View();
}
}
View - Index (Segment)
<table>
#foreach (var x in Model)
{
<tr>
<td>#Html.ActionLink(x.newsTitle, "NewsItem", new { newsId = x.newsID, newsTitle = x.newsTitle.ToSeoUrl() })
</td>
</tr>
}
</table>
Actionlink produces: News/NewsItem?newsId=3&newsTitle=my-news-item
I want: News/3/my-news-item
One way you could do this is to introduce an additional route into the route configuration
RouteConfig.cs:
routes.MapRoute(
name: "News_seo_friendly",
url: "{controller}/{id}/{seo}",
defaults: new { action = "NewsItem", seo = UrlParameter.Optional }
);
*Note the action value in this route. You will need a corresponding action method on that controller.
Also, since this route is more specific it goes above the existing, more generic route(s)
An Alt RouteConfig.cs that might be safer:
routes.MapRoute(
name: "News_seo_friendly",
url: "News/{id}/{seo}",
defaults: new { controller = "News", action = "NewsItem", seo = UrlParameter.Optional }
);
NewsController:
public ActionResult NewsItem(string id)
{
return View();
}
Another way you could do this is to make "News" its own Area within the project. This gives you the opportunity to isolate your routes, if your app is larger, and flexibility for your controller name(s).
Edited after feedback
Wanted to draw attention to the fact that the parameter name on the controller's NewsItem() method should match what is being declared in the route settings. In the above scenario, url: "{controller}/{id}/{seo}"
should match the parameter name in NewsItem(string id)...or vice-versa.

How switch Route when using method Url.Action in UrlHelper MVC4

I have following define route ,
routes.MapRoute(
name: "sp",
url: "sp/{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "pm",
url: "pm/{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional }
);
when running, url of my project like to "http://example.com:7549/nhj/pm" and "http://example.com:7549/nhj/sp"
But, when using method Url.Action("Edit", "Product"), the Url has been generated by method Url.Action is always "http://example.com:7549/nhj/sp/Product/Edit".
How can I use the method Url.Action("Edit", "Product") to generate two different urls that are "http://example.com:7549/nhj/pm/Product/Edit" and "http://example.com:7549/nhj/sp/Product/Edit" match with 2 routes above.
Anyone can you help me??? Thanks
Use Url.RouteLink() that is using the route name when generating the Url:
// for SP route
Url.RouteUrl("sp", new { action = "Edit", controller = "Product" });
// for PM route
Url.RouteUrl("pm", new { action = "Edit", controller = "Product" });
When you're using the returned Url to redirect from action, use:
// for SP route
return RedirectToRoute("sp", new { action = "Edit", controller = "Product" });
// for PM route
return RedirectToRoute("pm", new { action = "Edit", controller = "Product" });
See MSDN.

MVC 4: Custom Routes

I see a lot of problems with MVC routes and I'm having a similar problem getting a route to match a URL.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//default route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute("Beer", "Beer/{beerid}", new { controller = "Beer", action = "Id", beerid = 0});
routes.MapRoute("Beer", "Beer/{beername}", new { controller = "Beer", action = "Name" });
BeerController Methods
public ActionResult Id(int beerid)
public ActionResult Name(string beername)
If I change the methods to the following,
public ActionResult Id(int? id)
public ActionResult Name(string id)
the default routing works with the following URLs:
http://localhost/Beer/Id/100
http://localhost/Beer/Name/Coors
But what I'm going for is just
http://localhost/Beer/100
http://localhost/Beer/Coors
Any ideas?
So a couple things here.
More specific routes should be placed before more general routes, because the first route that is matched will be used and routes are inspected in the order they are added.
If you plan on not providing the name of the action in your URL then you will need to do something to ensure the correct route is targeted so the correct default value will be used. In your case you could use a route constraint to distinguish between the two. Try changing your beer id route to this:
routes.MapRoute(
name: "Beer",
url: "Beer/{beerid}",
defaults: new { controller = "Beer", action = "Id", beerid = 0},
constraints: new { beerid = #"\d+" }
);
The constraint will ensure that the route only matches two-segment URLs where the second segment is composed of one or more digits. This route as well as your route for beer name should be placed before the default route.
UPDATE
My configuration seems to be yielding the results you want. The entirety of my RegisterRoutes method is as follows:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Id",
url: "Beer/{beerid}",
defaults: new { controller = "Beer", action = "Id", beerid = 0 },
constraints: new { beerid = #"\d+" }
);
routes.MapRoute(
name: "Name",
url: "Beer/{beername}",
defaults: new { controller = "Beer", action = "Name" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

ASP.NET MVC 4: One controller routing is not like the others

I have added a new controller, "LoggingController" to an MVC 4 application that already has several controllers.
Now I noticed that the routing behaviour for this controller is different from those that already existed.
For example, the following two urls work properly, as expected, and hit the "Index" method in BlogController.
http://localhost:56933/Blog/
http://localhost:56933/Blog/Index
So do all other controllers except the one I added:
http://localhost:56933/Logging/Index - works properly, hits the "Index" method in LoggingController
http://localhost:56933/Logging/ - returns "Server Error in '/' Application. The resource cannot be found."
Where should I start looking, beyond the obvious things?
Here is the Index signature from LoggingController
public ActionResult Index(int? page, string Period, string LoggerProviderName, string LogLevel, int? PageSize)
There is nothing specific to a certain controller in the MapRoute. Here is the full RouteConfig for reference:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Display",
url: "Post/{id}/{seofriendly}",
defaults: new { controller = "Post", action = "Display", id = UrlParameter.Optional, seofriendly = ""}
);
routes.MapRoute(
name: "SEOFriendly",
url: "{controller}/{action}/{id}/{seofriendly}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, seofriendly = "" }
);
routes.MapRoute(
name: "SEOFriendlyNoId",
url: "{controller}/{action}/{seofriendly}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, seofriendly = "" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Your Index method doesn't actually have a signature matched by any of your available routes. You'll have to either provide defaults to your Index action or add an additional route to the beginning of your route table to specify those defaults. For Example:
routes.MapRoute(
name: "LoggingDefaults",
url: "Logging/{Period}/{LoggerProviderName}/{LogLevel}/{page}/{PageSize}",
defaults: new {controller = "Logging",
action = "Index",
page = UrlParameter.Optional,
PageSize = UrlParameter.Optional,
LoggerProviderName = "SomeProvider",
Period = "SomePeriod",
LogLevel = "SomeLevel"}