Search code examples
c#routesnancy

Dynamic Routes in NancyFx


I need to be able to dynamically route in NancyFx. Think of a blog, or a dynamic CMS that uses url-slugs to identify a particular blog/page. I suppose, if it were written in NancyFx, SO would be doing something of the sort...

Since there could be thousands of different url-slugs (page content pulled from a database), pre-building a routing table is not the best approach.

I've tried to do the following, in the constructor of my NancyModule:

public HomeModule()
{
   ...
   foreach (var page in pages)
   {
       Get(page.Slug, args => GetPage(page.Slug));
   }
}

This sort of works, but has the following limitations:

  1. The routes are build once, at the start of the web application (NancyFx caches all routes it discovers at the beginning). Any new routes (pages or blog entries with their unique slugs) that may be dynamically added later at runtime are not recognized.

  2. All routes are pre-built, even though only a few will likely be visited. This is super wasteful if the list of pages/unique slugs is in the thousands.

Can anyone suggest a strategy for routing dynamically in NancyFx, that is - as pages with unique slugs are dynamically added - how do I route to the default PageModule with the different slugs? Also, pre-defined modules with their routes should still be honored. For example, I want these URLs to route to the HomeModule:

/
/topic1
/topic2
/topic3
... 

(and any number of other topics, except those specifically listed below) but the following have their own modules that handle them, i.e. if there is a page/blog post defined with the conflicting slug, it would not be reachable:

/admin
/gallery
/image

NOTE: If possible, I specifically want to avoid the need for a specialized module segment in the URL, as in /page/{page-slug}. If page-slug is not predefined in another module, I want the catch-all HomeModule to handle it.


Solution

  • Routes are weighted in Nancy, meaning something very specific will be picked over something less specific.

    If you defined:

    Get("/admin", ...);
    Get("/gallery", ...);
    Get("/image", ...);
    Get("/{topic}", ...);
    

    A call to http://test.com/admin will be picked up by the more specific route which being /admin and not the less specific catch all route /{topic}

    Further more you cannot dynamically add routes unless your list was defined once upfront, because these are parsed on first load and cached so only a lookup is done when the first request comes through.

    You don't want to add 100s of specific routes, this would increase the lookup time and hinder perf (if you care about milliseconds)

    The route weights are defined here:

    https://github.com/NancyFx/Nancy/wiki/Defining-routes#pattern

    As you can see, a specific route is weighted at 10,000 while a catch all is weighted at 1000.