How to route tree URLs using ASP.NET routing?

I would like to achieve something very similar to this question with some improvements.

There is an ASP.NET MVC web application.

I have an entity tree.
For example, the Page class, which has the "Children" property, which is of type IList<Page> . (An instance of the Page class corresponds to a row in the database.)

Please note that site owners can add a new page at any time or delete existing ones, and URLs should also reflect these changes.

I would like to assign a unique URL for each Page in the database.
I process Page objects using a controller called PageController .

URL examples:

 http://mysite.com/Page1/ http://mysite.com/Page1/SubPage/ http://mysite.com/Page/ChildPage/GrandChildPage/ 

You will get a picture.
Therefore, I would like each Page object to have its own URL, which is equal to its parent URL plus its own name.
In addition to this, I would also like to map one Page to the / (root) URL.

I would like to apply the following rules:

  • If the URL can be processed by any other route, or if the file exists in the file system of the specified URL, suppose that the default mapping is displayed.
  • If the URL can be processed by the virtual path provider, let this handle it
  • If no other, map the other URLs to the PageController class

I also found this question , and also this and this , but they did not help much, since they do not give an explanation about my first two points.

I see the following possible rules:

  • Set up a route for each page. This requires me to navigate the entire tree when the application starts and add the exact matching route to the end of the route table.
  • I could add a route using {*path} and write a custom IRouteHandler that handles it, but I cannot figure out how I could handle the first two rules, since this handler could handle everything.

So far, the first solution seems to be correct, because it is also the simplest. But still, even in this case, I'm not sure how I can get PageController process requests.

I would really appreciate your thoughts on this.

Thank you in advance!

EDIT: I had time to study all aspects of every answer I received. I accepted Neil's answer as it gives a better explanation of how everything works. I also supported all the other answers as they give good ideas.

+6
asp.net-mvc routing asp.net-routing
source share
4 answers

Routes are processed in the order in which they are added to the collection. You can add your own route after existing routes to make sure that this is the last chance to be able to process the request. This will allow you to add routes to existing files (virtual or otherwise) in front of it and, therefore, meet criteria 1 and 2.

By default, MVC routing will be routed to existing files before applying any routes stored in the route collection; see http://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.routeexistingfiles.aspx . (hattip to Paul - see comments).

To redirect requests to your page controller, simply create a custom route that explores the virtual path, and if it matches the template for the page in the database, returns RouteData . Configure your RouteData with the appropriate values ​​extracted from the virtual path (for example, set the Path key to / Parent / Child / Great Student), set the controller key to the name of the page controller (for example, Page), and the action to the name of the action that you want to execute (e.g. Show). RouteData must be created using MvcRouteHandler (not sure if this is the correct class name).

To ensure that the URLs on the database-driven pages are correct, override the GetVirtualPath( RequestContext, RouteValueDictionary ) RouteBase and use the passed route values ​​to determine if this page is a managed database and if it creates the virtual path required data (or return otherwise).

For help with overriding GetRouteData and GetVirtualPath look at the source code for the reflection of System.Web.Routing.RouteBase and System.Web.Routing.Route ; after that google is your friend.

Routes are used in reverse order to determine the URL specified by the controller, action, and any other route values. You should use this to create the URL of the page in the context that is being requested.

+3
source share

Another idea is to use T4 (Text Template Transformation Toolkit) to read your children once and generate the contents of your Global.asax file.

EDIT: Bascially with T4 you can automate the creation of text files. For example, instead of manually copying elements of some huge collection and pasting them with a specific context into a text file (for example, INSERT INTO [MyTable] (Text) VALUES (@ItemText) ), you could force the T4 engine to read the collection and generate these insert instructions for you. It is static and not intended for the runtime.

I find a very good introduction to the book Pro Entity Framework 4.0 .

But if you say that you need to do this dynamically, this may not be for you.

+1
source share

You know the structure of your pages when you save the page. This way you can create a URL for each page and save it in a database record. Then you can use the rule {*path} and find the exact match in the database. This rule should be the last in the rule definition, so you can map other routes.

For example, your Page1 does not have a parent page; this is the URL of Page1 . Your SubPage knows its parent so that it can ganarate url Page1/SubPage , etc.

+1
source share

You can use the "Page/{*path}" template. Then you can either expand the path by dividing the string by "/" and going through it, or you can use Rarush’s suggestion to save the [generated] path to the database and perform a direct search.

If you use the Rarouš method, you will need to update the path entries in your table for all children when the parent path changes. This can be done quite simply with a single update request.

Assuming you map the page you want to use for the home page somewhere in a configuration file or in a table entry. You can have your home page controller, or search and return the contents to view the home page for rendering (you can use the general view, partial view or call in the page manager so that you do not duplicate the behavior), or you can redirect to this page.

Using this method, you can have a one-page controller and a view that processes all of these pages in the same way. Your other requirements appear to be handled automatically using the MVC framework.

Your path will look like this:

 http://mysite.com/Page/Page1/ http://mysite.com/Page/Page1/SubPage/ http://mysite.com/Page/Page/ChildPage/GrandChildPage/ 

Of course, you can use a prefix other than "Page".

+1
source share

All Articles