Reputation: 495
I have an index page which displays Categories (which have attributes: id and name) with the URL request: http://localhost:62745/home/index
.
When I click a category, I am taken to http://localhost:62745/Home/Products/6
.
I want to make the URL more detailed and replace the Category Id property 6
in the previous URL with the name
property of the Category which was just clicked.
My route config look like this:
public class RouteConfig
{
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: "Categories",
url: "{controller}/{action}/{categoryName}",
defaults: new { controller = "Category", action = "Index", categoryName = UrlParameter.Optional }
);
}
}
The first MapRoute()
method was already implemented. I added the second one hoping to solve my problem, but it didn't.
This is my controller action for products:
// GET: Product
public async Task<ActionResult> Index(int? id, string categoryName)
{
var products = (await db.Categories.Where(c => c.Id == id)
.SelectMany(p => p.Products.Select(x => new ProductViewModel { Id = x.Id, Name = x.Name, ByteImage = x.Image, Price = x.Price}))
.ToListAsync());
categoryName = db.Categories.Where(c => c.Id == id).Select(c => c.Name).ToString();
if (products == null)
{
return HttpNotFound();
}
return View(new ProductIndexViewModel{ Products = products, CategoryId = id });
}
Upvotes: 0
Views: 488
Reputation:
Both your routes are identical in terms how they are interpreted - they accept 2 segments and an optional 3rd segment, so Home/Products/6
and Home/Products/CategoryName
both match the first Default
route (there is nothing unique to distinguish the 2nd Categories
route so it will never be hit.
Your question refers to a Products()
method in the 2nd url, but you have not shown that method, so its not clear if your referring to a product name or a category name, but the principal is the same.
Assuming you want the url to be Home/Products/ProductName
to display a specific product, then in the view
@foreach(var item in Model.Products)
{
// link for each product
@Html.ActionLink("Details", "Products", "Home", new { id = item.Name }, null)
Then you can simply make the method
public ActionResult Products(string id)
{
// the value of id is the the the product name
....
}
Alternatively, if you want the parameter to be string name
rather that string id
, then you can define a specific route and place it before the Default
route.
routes.MapRoute(
name: "ProductDetails",
url: "Home/Products/{name}",
defaults: new { controller = "Home", action = "Products", name = UrlParameter.Optional }
);
so that the method becomes
public ActionResult Products(string name)
Side note: The fact you have a query in the Index()
method to get the category name suggests you might also be wanting a 'slug' route, in which case, refer how to implement url rewriting similar to SO.
Upvotes: 1