I have a product category table to represent a hierarchical category structure, a typical Parent-Child
relationship table in the database.
Fill it with Guitar Center's data as an example:
If you render them to a page with <ul>
and <li>
:
Texts in blue are the URLs I would like to generate. For any given category, the link consists of its slug and its parents' slugs.
Note that the example I listed only has 2 parent-child levels. In theory, with the self-referential structure, any child could have infinite parents.
Questions:
- How to set up routing template to achieve that?
- If the routing template is set up to support that, how to retrieve the leaf category? For example, from the URL
categories/guitars/acoustic-guitars
, I would like to retrieveacoustic-guitars
as the leaf category, and able to get all products under thatacoustic-guitars
category. Note: I don't want manual parsing on the URL. Ideally it would be the best if the lead category is binded through model binding.
You can't. But you can drop to a lower level and make a data-driven
IRouter
implementation for CMS-style route management.An Example:
CachedRoute<TPrimaryKey>
Here is an example that tracks and caches a 1-1 mapping of primary key to URL. It is a generic class and I have tested that it works whether the primary key is int or Guid.
There is a pluggable piece that must be injected,
ICachedRouteDataProvider
where the query for the database can be implemented. You also need to supply the controller and action, so this route is generic enough to map multiple database queries to multiple action methods by using more than one instance.CategoryCachedRouteDataProvider
Here we lookup the categories from the database and recursively join the slugs into a URL.
CategoryController
There is nothing special going on in the controller, except for the fact that we don't need to deal with a URL or a slug at this point at all. We simply accept the
id
parameter that maps to the primary key of the record and then you know what to do from there...Usage
We configure this in
Startup.cs
as follows:Note that the
CachedRoute<TPrimaryKey>
can be reused to create additional routes for other tables. So, if you wanted to, you could also make your product URLs likeguitars/acoustic-guitars/some-fancy-acoustic-guitar
by using a join on the Category table and using a similar method to build the URL.The URLs can be generated and added to the UI using Tag Helpers or any of the other
UrlHelper
based methods. For example:Which is generated as
You can of course then use the primary key of the model to generate the URL and the text for the link - it is all automatic and straightforward using models that have the primary key and name.
The only thing extra you would need to do is to create the hierarchy for the link display. But that is outside of the scope of routing.
Note that there is no concept of hierarchy at all in routing - it is simply a list of routes that is matched from top to bottom on each request.
It is unclear why you would need a "leaf category" as this has nothing to do with incoming or outgoing routes, nor is it required to lookup the database data. Again, the primary key is all you need to generate the entire URL based on routing and it should be all that is required to view all of the products. But if you really need access to it you can look it up in your controller.
Customization
You may need to change the caching strategy depending on your specific requirements.