I have solved it like this.
Added a new route that hits on everything that nopcommerce does find.
routes.MapLocalizedRoute("RouteName",
"{*slug}",
new { controller = "Routing", action = "DetermineControllerAndAction" },
new[] { "Nop.Web.Controllers" });
Created the new controller and added the method.
public class RoutingController : BaseNopController
{
private readonly IUrlRecordService _urlRecordService;
public RoutingController(IUrlRecordService urlRecordService)
{
_urlRecordService = urlRecordService;
}
public ActionResult DetermineControllerAndAction(string slug)
{
var record = _urlRecordService.GetBySlug(slug);
var data = CreateRouteData(record);
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var request = new RequestContext(context, data);
var controller = ControllerBuilder.Current.GetControllerFactory()
.CreateController(request, data.Values["controller"].ToString());
controller.Execute(request);
return new EmptyResult();
}
/// <summary>
/// Creates the RouteData object so the right controller and action is executed
/// </summary>
private RouteData CreateRouteData(UrlRecord record)
{
var data = new RouteData();
//Show page not found if record is null
if (record == null)
{
data.Values["controller"] = "Common";
data.Values["action"] = "PageNotFound";
return data;
}
//Handle 301
if (!record.IsActive)
{
var activeSlug = _urlRecordService.GetActiveSlug(record.EntityId, record.EntityName, record.LanguageId);
if (!string.IsNullOrWhiteSpace(activeSlug))
{
//the active one is found
var webHelper = EngineContext.Current.Resolve<IWebHelper>();
var response = System.Web.HttpContext.Current.Response;
response.Status = "301 Moved Permanently";
response.RedirectLocation = string.Format("{0}{1}", webHelper.GetStoreLocation(false), activeSlug);
response.End();
}
else
{
//no active slug found
data.Values["controller"] = "Common";
data.Values["action"] = "PageNotFound";
return data;
}
}
try
{
switch (record.EntityName)
{
case "Category":
data.Values.Add("controller", "Catalog");
data.Values.Add("action", "TransferToCategory");
data.Values.Add("categoryId", record.EntityId);
data.Values.Add("SeName", record.Slug);
break;
case "Product":
data.Values.Add("controller", "Catalog");
data.Values.Add("action", "TransferToProduct");
data.Values.Add("productId", record.EntityId);
data.Values.Add("SeName", record.Slug);
break;
}
return data;
}
catch (Exception e)
{
}
return null;
}
}
At last, added two methods to the CatalogController that just calls the original nop methods of category and product.
[NopHttpsRequirement(SslRequirement.No)]
public ActionResult TransferToCategory(int categoryId)
{
return Category(categoryId, new CatalogPagingFilteringModel());
}
[NopHttpsRequirement(SslRequirement.No)]
public ActionResult TransferToProduct(int productId)
{
return Product(productId);
}
This way, I can for example add to the urlrecord table "category/subcategory" and "category/subcategory/productname" and get a more dynamic routing and still use all the nopcommerce methods out of the box.