Let's say I have a node under mysite/products and I like it to catch all routes underneath, mysite/products/A , mysite/products/B - and handle the rest of the url myself from a macro on the template for mysite/products.
I don't think I can do that with any current package or built in behaviour? Other than manually adding urlrewriter rules.
So, I made a small 404 handler to achieve that behaviour. The handler simply looks for a "umbracoCatchAll" property in all parent urls above a not found url, and redirects to that one if found.
So this is a question for comments and for info about existing solutions. Before I make a package.
thanks, yes, but I never really liked that approach, editing a config file, plus the syntax is a bit hard/different. I like to handle these things in my node tree and use the same kind of syntax I'm familiar with:
I add the umbracoCatchAll=1 to my node on the /mysite/products , and then I add a razor script like this:
@{
var productBrand = CatchAll.UrlParts[0];
var productName = CatchAll.UrlParts[1];
var product = SomeDb.SingleOrDefault<dynamic>("SELECT * FROM Product WHERE Brand=@0 AND Name=@1", productBrand, productName);
}
<h1>@product.Description</h1>
<img src="@product.ImageUrl"/>
ยจ
... and I can show db stored products under my /mysite/products urls
CatchAll.UrlParts is a static helper function that splits all parts of the url that are to the right of the current node url (the same exists in WebPages)
I've never tried it yet but I still have an open project that requires the same behavior as yours. Another and perhaps better approach for you would be defining your custom routes in a class that inherits from IApplicationEventHandler:
I do unterstand that you don't like the config file approach (me neither), but we still work with a CMS that has some limitations but offers more opportunities. I personally would not overwrite the error file, even when you are checking that the target node exists.
Afaiu custom-routes takes me out of Umbraco pipeline, which I do not like in this case. I like to maintain the product pages template the same way I do with the others.
Surface controllers is for child actions, and would not handle the routes for me.
True, the 404 handler does seem like an unusual way to catch routes, and it would indeed feel a bit more correct to add a custom route handler of some kind, to happen before the umbraco route handler, not least to make it quick. However, it's still only a way to deal with the routing handler pipeline, even if its called 404 handlers, and I think the extra performance cost is small.
You may be right, but I was so sure there is another way... perhaps someone else knows more about it or finds the blog entry I cannot found any more ;-)
Unfortunately I cannot tell you more at the moment. I'm going to have a closer look at it as soon as possible, but currently I'm too busy.
If I understand correctly you have a url that may look like /path/to/our/products/category/product and products is a catch-all node, and /category/product does not actually exist in the tree, right?
Of course the first thing that comes to mind is a rewriting rule that would rewrite to /path/to/our/products?show=category/product but I understand you'd rather avoid rewriting rules.
In 6.1+ you'd create an IContentFinder... and in anything before you need to create a NotFoundHandler. So, since you're on 4.x, you need a NotFoundHandler. Yours seems OK in that context. Though maybe you can avoid recursion when trying the different urls?
Also... uQuery.GetNodeByUrl(...) uses the IContentFinder to find content (even in 4.x, only in 4.x IContentFinder are still internal) and there's some efficient cache in there... so instead of looking for /path/to/our/products/category/product then /path/to/our/products/category then... I'd rather do /path then /path/to then /path/to/our... because these are going to be _fast_. You keep track of which has the umbracoCatchAll property and use the last one that was found.
Also you could optimize if you know how many items /category/products will contain...
I changed the code to better performance, and then I remembered a discussion I had with (um, I forgot who, sorry...) that it would be nice to be able to just add a document named * and it should catch all sibling url calls.
For example /products/* will catch /products/foo and /products/bar as well as /products/bar/12345.
I like that better than having to add another property. The handler now supports both alternatives. Code is still in need of some polish.
Anyone has a "Catch all routes under node url" ?
Let's say I have a node under mysite/products and I like it to catch all routes underneath, mysite/products/A , mysite/products/B - and handle the rest of the url myself from a macro on the template for mysite/products.
I don't think I can do that with any current package or built in behaviour? Other than manually adding urlrewriter rules.
So, I made a small 404 handler to achieve that behaviour. The handler simply looks for a "umbracoCatchAll" property in all parent urls above a not found url, and redirects to that one if found.
So this is a question for comments and for info about existing solutions. Before I make a package.
https://gist.github.com/joeriks/5630458
Thanks
Jonas
You add rewrites in the UrlRewriting.config file. Would that help?
Hi,
thanks, yes, but I never really liked that approach, editing a config file, plus the syntax is a bit hard/different. I like to handle these things in my node tree and use the same kind of syntax I'm familiar with:
I add the umbracoCatchAll=1 to my node on the /mysite/products , and then I add a razor script like this:
ยจ
... and I can show db stored products under my /mysite/products urls
CatchAll.UrlParts is a static helper function that splits all parts of the url that are to the right of the current node url (the same exists in WebPages)
What do you think?
Well perhaps you can achieve your desired behavior with a plugin controller that defines an area:
http://our.umbraco.org/documentation/Reference/Mvc/surface-controllers
I've never tried it yet but I still have an open project that requires the same behavior as yours. Another and perhaps better approach for you would be defining your custom routes in a class that inherits from IApplicationEventHandler:
http://our.umbraco.org/documentation/Reference/Mvc/custom-routes
I do unterstand that you don't like the config file approach (me neither), but we still work with a CMS that has some limitations but offers more opportunities. I personally would not overwrite the error file, even when you are checking that the target node exists.
Afaiu custom-routes takes me out of Umbraco pipeline, which I do not like in this case. I like to maintain the product pages template the same way I do with the others.
Surface controllers is for child actions, and would not handle the routes for me.
True, the 404 handler does seem like an unusual way to catch routes, and it would indeed feel a bit more correct to add a custom route handler of some kind, to happen before the umbraco route handler, not least to make it quick. However, it's still only a way to deal with the routing handler pipeline, even if its called 404 handlers, and I think the extra performance cost is small.
Jonas
You may be right, but I was so sure there is another way... perhaps someone else knows more about it or finds the blog entry I cannot found any more ;-)
Unfortunately I cannot tell you more at the moment. I'm going to have a closer look at it as soon as possible, but currently I'm too busy.
Regards
Thanks for the discussion, I'll play around with this to begin with and see what happens :)
If I understand correctly you have a url that may look like /path/to/our/products/category/product and products is a catch-all node, and /category/product does not actually exist in the tree, right?
Of course the first thing that comes to mind is a rewriting rule that would rewrite to /path/to/our/products?show=category/product but I understand you'd rather avoid rewriting rules.
In 6.1+ you'd create an IContentFinder... and in anything before you need to create a NotFoundHandler. So, since you're on 4.x, you need a NotFoundHandler. Yours seems OK in that context. Though maybe you can avoid recursion when trying the different urls?
Also... uQuery.GetNodeByUrl(...) uses the IContentFinder to find content (even in 4.x, only in 4.x IContentFinder are still internal) and there's some efficient cache in there... so instead of looking for /path/to/our/products/category/product then /path/to/our/products/category then... I'd rather do /path then /path/to then /path/to/our... because these are going to be _fast_. You keep track of which has the umbracoCatchAll property and use the last one that was found.
Also you could optimize if you know how many items /category/products will contain...
Stephan
Hi Stephen, thank you very much for your feedback!
Yep, that's the way I meant the urls to behave.
Ok, changing to search from the shortest url first, makes sense, esp if there's a lot of urlparts outside, thx.
Good to know about the IContentFinder. Will explore that for a future version :)
Cheers
Jonas
I changed the code to better performance, and then I remembered a discussion I had with (um, I forgot who, sorry...) that it would be nice to be able to just add a document named * and it should catch all sibling url calls.
For example /products/* will catch /products/foo and /products/bar as well as /products/bar/12345.
I like that better than having to add another property. The handler now supports both alternatives. Code is still in need of some polish.
https://gist.github.com/joeriks/5630458
is working on a reply...