Outbound request pipeline

Learn how the Umbraco outbound request pipeline works.

The outbound pipeline consists out of the following steps:

To explain these steps, the following content tree is used as an example:

Content Tree

1. Create segments

When a URL is constructed, Umbraco converts every node in the tree into a segment. Each published content item has a corresponding URL segment.

In the example above, "Our Products" becomes "our-products" and "Swibble" becomes "swibble".

Segments are created by the URL Segment Provider.

URL Segment Provider

The Dependency Injection (DI) container of an Umbraco implementation contains a collection of UrlSegmentProviders. This collection is populated during Umbraco startup. Umbraco ships with a 'DefaultUrlSegmentProvider', but custom implementations can be added to the collection.

When the GetUrlSegment extension method is called for a content item and culture combination, each registered IUrlSegmentProvider in the collection is executed in collection order. This continues until UrlSegmentProvider returns a segment value for the content. No further UrlSegmentProviders in the collection are executed after that point. If no segment is returned by any provider in the collection, the DefaultUrlSegmentProvider is used as a fallback. This ensures that a segment is always created.

To create a new URL Segment Provider, implement the IUrlSegmentProvider interface:

circle-info

Each culture variation can have a different URL segment.

The returned string becomes the URL segment for the node. The value cannot contain the URL segment separator character /. A value such as 5678/swibble would create additional segments, which is not allowed.

Example

The following example adds the unique SKU or product reference of a product page to the existing URL segment.

The returned string becomes the native URL segment. There is no need for URL rewriting.

For the "swibble" product in the example content tree, ProductPageUrlSegmentProvider returns the segment swibble--123xyz, where 123xyz is the unique product SKU for the swibble product.

Register the custom UrlSegmentProvider with Umbraco using a composer:

The Default URL Segment Provider

The Default URL Segment Provider builds segments by checking for one of the following values, in this order:

  1. A property with alias umbracoUrlName on the node. This is a convention-based way to give editors control of the segment name. With variants, this can vary by culture.

  2. The name of the content item, for example content.Name.

The Umbraco string extension ToUrlSegment() is used to produce a clean, URL-safe segment.

2. Create paths

To create a path, the pipeline uses the segments of each node.

In the example, the "swibble" node receives the path /our-products/swibble. Using the ProductPageUrlSegmentProvider from above, the path becomes /our-products/swibble-123xyz.

Multiple sites in a single Umbraco implementation

In a multi-site scenario, an internal path such as /our-products/swibble-123xyz could belong to any of the sites, or match multiple nodes across multiple sites. In this case, additional sites have their internal path prefixed by the node ID of their root node. Any content node with a hostname defines a new root for paths.

Path example
Node
Segment
Internal Path

Our Values

our-values

/our-values

Our Products

our-products

/our-products

Swibble

swibble-123xyz

/our-products/swibble-123xyz

Dibble

dibble-456abc

/our-products/dibble-456abc

Another Site

another-site

9676/

Their Values

their-values

9676/their-values

Paths can be cached. Scheme, domain, and current request cannot be cached.

Considerations when working with Hostnames

  • Domain without path: www.site.com produces 1234/path/to/page.

  • Domain with path: www.site.com/dk produces 1234/dk/path/to/page.

  • No domain specified: /path/to/page.

  • HideTopLevelNodeFromPath set to true: the path becomes /to/page.

3. Creating URLs

The URL of a node consists of a complete URIarrow-up-right: the Schema, Domain name, port, and path.

In the example, the "swibble" node has the URL: http://example.com/our-products/swibble.

URL generation is handled by the URL Provider. The URL Provider is called whenever a URL is requested in code, for example:

The DI container of an Umbraco implementation contains a collection of UrlProviders. This collection is populated during Umbraco startup. Umbraco ships with a DefaultUrlProvider, but custom implementations can be added to the collection. When .Url is called, each IUrlProvider in the collection is executed in collection order until a particular IUrlProvider returns a value.

DefaultUrlProvider

Umbraco ships with a DefaultUrlProvider, which maps the structure of the content tree to URLs out of the box. In Umbraco 15 and later, this is implemented as NewDefaultUrlProvider.

How the Default URL provider works

  • If the current domain matches the root domain of the target content, return a relative URL. Otherwise, return an absolute URL.

  • If the target content has one root domain, use that domain to build the absolute URL.

  • If the target content has more than one root domain, determine which one to use to build the absolute URL.

  • Complete the absolute URL with the scheme (HTTP or HTTPS). Use the scheme from the domain if one is specified; otherwise use the current request scheme.

  • If addTrailingSlash is true, add a trailing slash.

  • Add the virtual directory.

If the URL provider encounters collisions when generating content URLs, it selects the first available node and assigns the URL to that node. The remaining nodes are marked as colliding and do not receive a generated URL. Fetching the URL of a node with a collision URL results in an error string that includes the node ID, for example #err-1094. This can happen when an umbracoUrlName property overrides the generated URL of a node, or when multiple root nodes exist without hostnames assigned.

circle-exclamation

Custom URL Provider

Create a custom URL Provider by implementing the IUrlProvider interface:

The UrlInfo object returned by GetUrl can contain a custom URL.

When implementing a custom URL Provider, consider the following:

  • Cache results where possible.

  • Handle schemes (HTTP vs HTTPS) and hostnames.

  • Inbound routing may require a matching IContentFinder.

circle-info

For small changes to URL generation logic, inherit from NewDefaultUrlProvider and override the GetUrl() virtual method rather than implementing IUrlProvider from scratch.

Example

This example replaces the default URL provider with a custom implementation, based on NewDefaultUrlProvider. The custom URL provider implements a new routing scheme for product pages.

circle-exclamation

Use a composer to replace the default URL provider with the custom implementation:

circle-info

To use multiple URL providers, add them with multiple Insert calls. Umbraco cycles through all registered providers until one returns a non-null value. If all custom providers return null, Umbraco falls back to the default URL provider. The last provider added with Insert is the first to execute.

GetOtherUrls

The GetOtherUrls method is used only in the Umbraco Backoffice. It provides editors with a list of other URLs that also map to the node.

For example, the convention-based umbracoUrlAlias property allows editors to specify a comma-delimited list of alternative URLs for a node. A corresponding AliasUrlProvider is registered in the UrlProviderCollection to display this list in the backoffice Info panel.

GetPreviewUrlAsync

Implement this method when the URL provider supports a custom preview URL scheme.

A common use case is providing external preview environments for headless sites. See Additional preview environments support for a complete example.

Most custom URL providers do not support this. A default implementation returning null is sufficient in those cases:

Url Provider Mode

The URL Provider Mode specifies whether the URL provider produces absolute or relative URLs. Auto is the default.

The available modes are:

Change the default setting in the Umbraco:CMS:WebRouting section of appsettings.json:

See WebRouting config reference documentation for more information on routing settings.

Site Domain Mapper

The ISiteDomainMapper implementation is used in the IUrlProvider. It filters a list of DomainAndUri objects to return the one that best matches the current request.

Create a custom SiteDomainMapper by implementing ISiteDomainMapper:

The MapDomain methods receive the current request URI. Custom logic determines which domain to use for a site in the context of that request. The SiteDomainMapper receives the current URI and all eligible domains, and returns the single domain used by the URL Provider to construct the URL.

Only a single ISiteDomainMapper can be registered with Umbraco.

Register the custom ISiteDomainMapper using the SetSiteDomainHelper extension method:

Default SiteDomainMapper

Umbraco ships with a default SiteDomainMapper that supports grouping sets of domains together. In a multi-environment setup such as Umbraco Cloud, multiple domains may be configured for a single site. For example, live, staging, testing, and a backoffice domain. Each domain is set up as a Culture and Hostname entry inside Umbraco.

Culture and Hostnames multiple domains

Without a SiteDomainMapper, editors see the full list of possible URLs for each content item across all configured domains:

All domains listed

This can lead to confusion. Clicking a staging URL may display content from a different environment or database.

To avoid this, use the default SiteDomainMapper's AddSite method to group related URLs together. Because the SiteDomainMapper is registered in the DI container, create a component to add the sites in the Initialize method:

Register the component with a composer:

When an editor visits the backoffice, the Links panel filters the displayed URLs to only those in the same site group as the current domain. An editor visiting via myproject-staging.euwest01.umbraco.io sees only the staging URL:

Staging domain only

An editor visiting via myproject-dev.euwest01.umbraco.io sees only the dev and live URLs:

Backoffice and production domains only
circle-info

This is a grouping, not a one-to-one mapping. Multiple URLs can be added to a group. In the example above, an editor visiting via myproject.euwest01.umbraco.io (the live domain) would also see myproject-dev.euwest01.umbraco.io listed, as both belong to the dev group.

Grouping the groupings - BindSites

The SiteDomainMapper includes a BindSites method to bind different site groupings together:

Visiting the backoffice via myproject-dev.euwest01.umbraco.io now lists all domains from both the dev and the staging group.

Last updated

Was this helpful?