The url parameter for MapUmbracoRoute is currently hard coded to products/{action}/{id}, to match the /products page URL. This works for now, but it will cause a problem if:
The page is moved to a different URL
Another page is created with the same document type at a different URL, or
A translated version of the page exists at a different URL, eg /es/products for Spanish.
Before I map the routes, I could search for all pages which use the Products document type and use the URL for each one as the prefix for a new mapping. But it seems like this must be a common problem, since a simple change in the backoffice could easily break things. Is there a shortcut method to do this?
It depends if your individual products exist as content items in Umbraco or are in some outside database/system.
If they are in Umbraco and have their own DocumentType then you don't need to map an MVC Route for them, you can use RouteHijacking (a convention based approach to map all requests to a particular document type to an MVC Controller) - https://our.umbraco.com/Documentation/Reference/Routing/custom-controllers
eg
public class ProductController : Umbraco.Web.Mvc.RenderMvcController
{
public ActionResult Index(ContentModel model)
{
// we will create a custom model
var myCustomModel = new MyCustomModel(model.Content);
// TODO: assign some values to the custom model...
return CurrentTemplate(myCustomModel);
}
}
So wherever the product is created, whatever it's url is, the request for it will be passed via this controller's index action...
If your products are outside of Umbraco...
Then you can map a custom route using MapUmbracoRoute, as I think you have - and implement your own accompanying VirtualNodeRouteHandler implementation (https://our.umbraco.com/Documentation/Reference/Routing/custom-routes) - the VirtualNodeRouteHandler can contain the logic to 'find' the products page wherever it is, and wherever it is named...
... but in doing so you are completely outside of Umbraco's request pipeline (this can be a good thing, but also has downsides eg handling a custom 404 page etc it becomes your responsibility) ...
... but if your idea is to give the editor control over the Route via the CMS then yes, this is much more complex to determine what editors are allowed to change, how to update the routes, and how to manage 301 redirects for the products to move to their new routing Url.
But if an editor renames 'Products' to be 'SuperProducts' then the route /products/display/123 will still 'work' ... depending on the logic to find the product, eg via the id etc...
what I'm saying is when you extend Umbraco in this way for a special Products integration, then you take on the responsibility of what happens if the url changes...
... but if your products are in Umbraco then using route hijacking is what you need!
Essentially every incoming request to Umbraco, fires a pipeline of a series of IContentFinders to map the Url to an IPublishedContent item...
... you can register your own IContentFinder, and write your own logic based on the url, of how to map to a particular product's IPublishedContent item...
... or ...
you can go off to a database or external system and create a new object that implements IPublishedContent and return 'Virtual' content from within the Umbraco pipeline to operate 'like' Umbraco Published Content.
So again this approach might give you much more flexibility over the incoming Url, and how it might change over time, and how it might map to a published content item, or even an item constructed with data outside of Umbraco than using a Mapped Route.
Custom route for all pages of a document type
I've set up a custom route very similar to the example at https://our.umbraco.com/documentation/reference/routing/custom-routes. Following that example, I have a page at /products with a document type of Products and a matching template which renders the content.
The url parameter for MapUmbracoRoute is currently hard coded to
products/{action}/{id}
, to match the /products page URL. This works for now, but it will cause a problem if:Before I map the routes, I could search for all pages which use the Products document type and use the URL for each one as the prefix for a new mapping. But it seems like this must be a common problem, since a simple change in the backoffice could easily break things. Is there a shortcut method to do this?
Hi Steve
It depends if your individual products exist as content items in Umbraco or are in some outside database/system.
If they are in Umbraco and have their own DocumentType then you don't need to map an MVC Route for them, you can use RouteHijacking (a convention based approach to map all requests to a particular document type to an MVC Controller) - https://our.umbraco.com/Documentation/Reference/Routing/custom-controllers
eg
So wherever the product is created, whatever it's url is, the request for it will be passed via this controller's index action...
If your products are outside of Umbraco...
Then you can map a custom route using MapUmbracoRoute, as I think you have - and implement your own accompanying VirtualNodeRouteHandler implementation (https://our.umbraco.com/Documentation/Reference/Routing/custom-routes) - the VirtualNodeRouteHandler can contain the logic to 'find' the products page wherever it is, and wherever it is named...
... but in doing so you are completely outside of Umbraco's request pipeline (this can be a good thing, but also has downsides eg handling a custom 404 page etc it becomes your responsibility) ...
... but if your idea is to give the editor control over the Route via the CMS then yes, this is much more complex to determine what editors are allowed to change, how to update the routes, and how to manage 301 redirects for the products to move to their new routing Url.
But if an editor renames 'Products' to be 'SuperProducts' then the route /products/display/123 will still 'work' ... depending on the logic to find the product, eg via the id etc...
what I'm saying is when you extend Umbraco in this way for a special Products integration, then you take on the responsibility of what happens if the url changes...
... but if your products are in Umbraco then using route hijacking is what you need!
The other trick worth being aware of when organising Urls to Umbraco Content are IContentFinders: https://our.umbraco.com/Documentation/Reference/Routing/Request-Pipeline/IContentFinder
Essentially every incoming request to Umbraco, fires a pipeline of a series of IContentFinders to map the Url to an IPublishedContent item...
... you can register your own IContentFinder, and write your own logic based on the url, of how to map to a particular product's IPublishedContent item...
... or ...
you can go off to a database or external system and create a new object that implements IPublishedContent and return 'Virtual' content from within the Umbraco pipeline to operate 'like' Umbraco Published Content.
So again this approach might give you much more flexibility over the incoming Url, and how it might change over time, and how it might map to a published content item, or even an item constructed with data outside of Umbraco than using a Mapped Route.
Hope that gives you some ideas.
regards
Marc
Thanks Marc, that's extremely helpful. My data is external, so I'm creating my own IContentFinder and returning 'virtual' content as you suggested.
Thanks!
is working on a reply...