Partial Routers
Outline
- SEO Extension: Maps URL segments to non-page data like external databases or the Dynamic Data Store (DDS)
- Core Interface: Uses IPartialRouter to resolve incoming requests and generate outgoing virtual paths for dynamic content
- State Management: Leverages IHttpContextAccessor to pass routed data to controllers, bypassing immutable route values in CMS 12
- Performance: Requires robust caching and segment validation to maintain site speed and prevent routing loops
In complex enterprise architectures, content often exists outside the standard CMS page tree. Optimizely CMS 12 provides Partial Routing as a robust mechanism to map specific URL segments to dynamic data sources such as external databases, product catalogs, or the Dynamic Data Store (DDS). This enables search-engine-friendly (SEO) URLs for non-page content while maintaining the context of a "parent" CMS page.
1. Technical Purpose and Use Cases
Standard routing in Optimizely resolves URLs by matching segments to the IContent hierarchy. Partial routing extends this logic by allowing a "pointing" content item (often a page) to handle the remaining URL segments manually. Common scenarios include:
- Dynamic External Data: Routing to news articles, blog entries, or product details stored in an external SQL database or DDS.
-
Hierarchical Dynamic Routing: Managing complex URL structures like
/news/category/article-name/where/news/is a CMS page and the rest is dynamic. - Pagination and Filtering: Handling URL segments purely for data filtering without creating physical child pages in the CMS tree.
2. The IPartialRouter<TContent, TRoutedData> Interface
The core of partial routing is implementing the IPartialRouter interface from the EPiServer.Core.Routing namespace. It uses two generic type parameters:
-
TContent: The CMS content type that acts as the routing anchor - for example,NewsContainerPage. -
TRoutedData: The non-page data type to which the URL resolves - for example, aNewsContentobject from an external store.
Core Interface Methods
Select a method to expand and read the details.
RoutePartial ▼
Invoked during incoming request resolution. It parses the URL segments following the resolved TContent anchor and determines which TRoutedData instance matches them. It must update RemainingSegments on the context to signal how much of the URL was consumed.
GetPartialVirtualPath ▼
Invoked during outgoing URL generation. It constructs a friendly URL based on a TRoutedData instance and its associated TContent anchor, enabling standard CMS helpers like Url.ContentUrl to generate accurate paths for dynamic objects.
3. Implementation Patterns for CMS 12
In CMS 12 (.NET 6/8), partial routing integrates with the underlying ASP.NET Core routing system. A critical change from legacy versions is the immutability of UrlResolverContext.RouteValues - routed data must be passed via alternative mechanisms.
Resolving Data in RoutePartial
The implementation reads URL segments from SegmentContext and updates the context to indicate how much of the URL was consumed.
Passing Data to Controllers
Since RouteValues cannot be directly modified in CMS 12, use IHttpContextAccessor to store routed data in the request's Items dictionary:
The corresponding controller retrieves the data from the same Items dictionary:
4. System Registration
Registration in CMS 12 is handled through the DI container - typically in the ConfigureServices method in Program.cs or a dedicated IServiceCollection extension method.
Note: Partial routers should be registered as Singleton since they hold no per-request state - the routed data is passed via HttpContext.Items, not the router instance itself.
5. Generating Outgoing URLs
To ensure links to dynamic content are SEO-friendly, the GetPartialVirtualPath method must be correctly implemented. This allows standard CMS helper methods like Url.ContentUrl to generate accurate paths for dynamic objects rather than falling back to raw IDs.
6. Performance and Best Practices
-
Caching: Partial routers are executed on every matching request. Ensure all lookup logic (database queries, external API calls) is backed by a robust caching strategy using
IContentCacheKeyorISignaledCachefor automatic invalidation. -
GUID Consistency: When routing to content that implements
IContentbut is not in the page tree, ensure it has a stable, unique GUID to support routing and Optimizely Graph indexing. - Segment Management: Always check for null or empty segments to avoid infinite routing loops or unnecessary database hits for malformed or crawler-generated URLs.
Pro tip: In high-traffic environments, wrap your data lookup in a memory cache keyed on the URL segment. An uncached RoutePartial that hits a database on every request will quickly become a bottleneck under load.
Conclusion
Partial Routers provide a sophisticated method for merging external and dynamic data into the standard Optimizely CMS URL structure. By leveraging IPartialRouter and modern .NET DI, developers can create highly scalable, performant, and SEO-optimized navigation systems that exist beyond the traditional content tree boundaries.
