Optional string parameter MVC Routing and ugly urls
I am using mvc 5.2.3 to 4.5.1 and want these urls
- / Nike / Shoes
- / Nike / Shoes / Running
- / Nike / Shirts / 2002342345
- / Nike / Shoes / Running / 98765432234
My controller has:
[HttpGet]
[Route("{brand}/{category}/{subcategory}/{page:int?}", Name="ProductIndex")]
public ActionResult Index(string brand, string category, int? page, string subcategory = "")
and gives / Nike / Shoes / Running but not / Nike / Shoes but / Products? brand = Nike & category = Shoes
When I add
[HttpGet]
[Route("{brand}/{category}/{page:int?}")]
public ActionResult Index(string brand, string category, int? page)
/ Nike / Shoes / works, but I also have / Nike / Shoes /? subcategory = Running
and my data method:
[HttpGet]
[Route("{brand}/{category}/{subcategory}/{productid:int:min(9000)}", Name="ProductDetails")]
public ActionResult Details(int productid)
gives:
The current request is ambiguous between the following ways: Index System.Web.Mvc.ActionResult (System.String, System.String, System.Nullable`1 [System.Int32], System.String) of type shopmvc.Controllers.ProductsController Index System.Web .Mvc.ActionResult (shopmvc.ViewModels.ProductsViewModel) of type shopmvc.Controllers.ProductsController System.Web.Mvc.ActionResult Details (Int32) of type shopmvc.Controllers.ProductsController
So, something is wrong with my product links and categories / subcategories. or with the way I am trying to achieve it:
<a href="@Url.RouteUrl("ProductDetails", new { brand = item.Brand, category = item.Category, subcategory = item.SubCategory, productid = item.ID })">test</a>
<a href="@Url.Action("Details", "Products", new { brand = item.Brand, category = item.Category, subcategory = item.SubCategory, productid = item.ID })">
<a href="@Url.Action("Index", "Products", new { brand = c.Brand, category = c.Category, subcategory = c.SubCategory })">@c.DisplayName</a>
source to share
How do I get the top general level and determine the rest from there?
[HttpGet]
[Route("{brand}/{category}/{*subdivision}", Name="ProductIndex")]
public ActionResult Index(string brand, string category, string subdivision)
Then determine if your division's division contains a deeper path or productID and calls the correct methods based on that choice
source to share
Have you tried ordering routes Global.asax
from most specific to most general? Your application doesn't know which order to check for routes, so something like this brand/category/subcategory/nnnnn
could be either on the nnnnn page or on the nnnnn product.
You need to check this route first:
[HttpGet]
[Route("{brand}/{category}/{subcategory}/{productid:int:min(9000)}", Name="ProductDetails")]
public ActionResult Details(int productid)
Then this:
[HttpGet]
[Route("{brand}/{category}/{subcategory}/{page:int?}", Name="ProductIndex")]
public ActionResult Index(string brand, string category, int? page, string subcategory = "")
Alternatively, you can change the route so that the page route is something like this:
`brand/category/subcategory/p-n`
eg. /Nike/Shoes/Running/p-2
EDIT: What happens if you do this? Any number less than 9000 will be interpreted as the number of pages, although this may confuse the user!
[HttpGet]
[Route("{brand}/{category}/{subcategory}/{page:int?:max:8999}", Name="ProductIndex")]
public ActionResult Index(string brand, string category, int? page, string subcategory = "")
source to share