Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Requirements for authenticating requests for the backoffice
In order for Umbraco to authenticate a request for the backoffice, the routing needs to be specific. Any URL that routes to:
/umbraco/backoffice/*
will be authenticated. If you have a controller that is not routed within the prefix, it will not be authenticated for backoffice use.
You do not have to worry about routing if you are using Umbraco.Cms.Web.BackOffice.Controllers.UmbracoAuthorizedApiController
(or any inherited controller) since these are auto routed. All implementations of UmbracoAuthorizedApiController
(which includes UmbracoAuthorizedJsonController
) are auto-routed with the default route:
/umbraco/backoffice/api/{controller}/{action}
In the case that an Umbraco Api Controller is a 'Plugin Controller', then the route would be:
/umbraco/backoffice/{pluginname}/{controller}/{action}
The {area} specified by the [PluginController] attribute replaces the /api/ area for the route.
Depending on the type of controller used (MVC or WebAPI), the controller is not auto-routed. You will need to declare a custom route and register it with the Umbraco DI container to make it work.
For more information on authenticated/authorized controllers & attributes see the Controllers Documentation.
Defining a route is done with the standard .NET Core MVC routing practices, however there is a handy extension method on the IEndpointRouteBuilder
to help you.
When creating custom routes you can either do it directly in the Startup.cs
files, or with a pipeline filter in a composer which looks something like:
The signature of MapUmbracoRoute<T>
is as follows
The generic type argument is the contoller you wish to route, in this case MyController
.
rootSegment
- The first part of the pattern, since this is an authorized controller it has to be umbraco/backoffice
.
areaName
- The name of the area the controller should be routed through, an empty string signifies no area.
prefixPathSegment
- Prefix to be applied to the rootSegment, we know this from api controllers where the prefix is api
, in this case since the controller is in an area we will also prefix the area name to the URL, so the final path pattern will be umbraco/backoffice/mypackagename/{controllerName}/{action}/{id?}
.
defaultAction
- If this is not null or an empty string the request will automatically be routed to the specified action, so in this case umbraco/backoffice/mypackagename/{controllerName}
will route to the index action.
includeControllerNameInRoute
- If this is false the controller name will be excluded from the route, so in this case the route would be umbraco/backoffice/mypackagename/{action}/{id?}
if this was set to false.
constraints
- Any routing constraints passed to this will be used when mapping the route see Microsoft documentation for more information.
The current implementation of XPath is suboptimal and will be removed entirely in a future version. It is currently obsolete and scheduled for removal in v14.
Using the MapUmbracoRoute
extension method is optional though, it's a neat helper to ensure controllers get routed in the same way. If your controller uses an area, like in this example, you need to specify this using the Area
attribute. In this example the controller looks like this:
The route must be prefixed with the Umbraco path, which is configurable and resolved with GetUmbracoMvcArea()
from IGlobalSettings
. Then, it should be followed by "/backoffice" in order for Umbraco to check user authentication.
Surface Controllers should not be used in the backoffice. Surface Controllers are not designed to work with the backoffice. They are not meant to be used there and will not be supported being used there.
Customizing the ASP.NET middleware pipeline in Umbraco
Middleware is responsible for processing/customizing an incoming request before generating an outgoing response. Shortly defined the middleware is a step to check the requests before giving a response back.
You can use Umbraco pipeline filters in case you want to add your own middleware before, in-between or after the default Umbraco middleware. Filters are added by configuring the UmbracoPipelineOptions
and require an instance of IUmbracoPipelineFilter
that contains the following callbacks:
PostPipeline
- executed after all Umbraco-specific middleware is added.
Endpoints
- executed right before the Umbraco-specific endpoints are added using WithEndpoints()
.
The addition of the PostRouting
callback is to allow correctly configuring the Cross-Origin Resource Sharing (CORS) middleware without having to use the WithCustomMiddleware()
method.
IUmbracoPipelineFilter
is an interface in Umbraco that allows the creation of custom filters which then modifies the behavior of the request pipeline. It can be used to change different aspects of how Umbraco handles incoming requests, such as changing content or adding security checks.
WithCustomMiddleware()
is a method that can be used in Umbraco for adding custom middleware. This includes some specific customizable instructions that run in the request processing pipeline.
Using WithCustomMiddleware()
instead of WithMiddelware()
should only be used as a last resort. This is because Umbraco can break if you forget to add middleware or add them in the wrong order.
Create a composer with the following:
You should be able to request /echo
from any origin, but get an error when trying to fetch /echo2
from a foreign origin. This can be tested by pasting the following JavaScript code in browser console when not on the local origin/Umbraco website (such as umbraco.com):
This should return the following:
An additional bonus is that this doesn't require any changes in your Startup.cs
file. It also allows packages to enable Cross-Origin Resource Sharing (CORS) and configure their own policies.
Users that currently use WithCustomMiddleware()
will need to add calls to RunPreRouting()
and RunPostRouting()
. This is similar to Umbraco adding additional middleware in future versions.
All about Umbraco's routing pipeline & the types of Controllers used in Umbraco
All about Umbraco's routing pipeline & the types of Controllers used in Umbraco, how they work, and what they are used for.
Explains how Umbraco builds its URLs and how the URLs are mapped back to content items.
Describes the Umbraco special/reserved Property Type aliases that can be used to directly manipulate Umbraco's default routing pipeline. These special Property Type aliases can be useful when creating an Umbraco website.
What is a Surface Controller and how to use them?
What is an API Controller and how to use them?
Creating custom controllers to have 100% full control over how your pages are rendered. Also known as: Hijacking Umbraco Routes
How to specify your own custom MVC routes in your Umbraco application?
Routing requirements for authenticated controllers for both front-end and the backoffice.
Moving and renaming Umbraco documents will lead to URL redirects to be created.
Use a custom MVC controller to handle and control incoming requests for content pages based on a specific Document Type, also called Route Hijacking.
Use a custom controller to handle and control incoming requests for content pages based on a specific Document Type
By default, all front-end requests to an Umbraco site are auto-routed via the 'Index' action of a core Controller: Umbraco.Cms.Web.Common.Controllers.RenderController
. This core controller handles the incoming request, builds the associated PublishedContent model, and passes this to the appropriate Umbraco Template/MVC View.
It is however possible to implement a custom Controller to replace this default implementation to give complete control over this execution.
For example:
To enrich the view model passed to the template with additional properties (from other published content items or outside Umbraco)
To implement serverside paging
To implement any custom/granular security
To return alternative templates depending on some custom business logic
This replacement of the default controller can be made 'globally' for all requests (see last example). It can also be by 'hijacking' requests for types of pages based on their specific Document Type following this controller naming convention: [DocumentTypeAlias]Controller
.
In the following example, imagine an Umbraco site with a set of 'product' pages created from a Document Type called 'Product Page' with an alias 'productPage'.
Create a custom locally declared controller in the Umbraco web application project named 'ProductPageController'.
Ensure that this controller inherits from the base controller Umbraco.Cms.Web.Common.Controllers.RenderController
.
eg:
All requests to any product pages in the site will be hijacked and routed through the custom ProductPageController.
If you prefer to use an async controller your need to override both the sync and the async Index()-methods. This is done to disable the default behavior from the base controller.
This example shows the default behavior that Umbraco's core RenderController provides. The 'Index' action of the controller is executed, and the CurrentTemplate helper sends the model containing the details of the published content item related to the request to the relevant template/view.
A further convention is that if an action on the controller has a name that matches the template name, this action will be executed instead of the default 'Index' action.
In this example, the Product Page Document Type has two templates 'ProductPage' and 'ProductAmpPage'. We can hijack and handle the requests to the two templates differently.
Create the Controller as before:
The page in Umbraco will have a single 'template' selected as it's default template, but it's possible to call this same page on a different template by adding ?altTemplate=othertemplatename
to the Url QueryString eg:
/products/superfancyproduct/?altTemplate=ProductAmpPage
Document Type name = controller name
Template name = action name (if no action matches or is not specified - then the 'Index' action will be executed).
Controller Inherits from Umbraco.Cms.Web.Common.Controllers.RenderController
The steps to achieve this will differ, depending if your template views are using IPublishedContent or Modelsbuilder generated Models.
By default, your Umbraco Template will be based on the ContentModel
that the default RenderController
passes through to it.
The default inherits statement:
or if you are using modelsbuilder:
<>
contains a model generated for each Document Type to give strongly typed access to the Document Type properties in the template view.
To use a specific custom view model, the @inherits
directive will need to be updated to reference your custom model using the Umbraco.Cms.Web.Common.Views.UmbracoViewPage<T>
format where 'T' is the type of your custom model.
So for example, if your custom model is of type 'MyProductViewModel' then your @inherits
directive will look like:
Views will likely specify a master view to use as the common layout for the site HTML. When using a custom view model it's necessary to make sure this doesn't conflict with any implementation in the master layout view. Eg. if your master layout view is inheriting from a specific model UmbracoViewPage<SpecificModel>
and using a property from SpecificModel that isn't available in your custom model an exception will be thrown. To avoid this you could:
Keep your Master layout view 'generically typed', eg. only have @inherits UmbracoViewPage
, and use Model.Value syntax to access properties. or
Break the dependency on Umbraco.Cms.Core.Models
in your master layout by having it instead inherit from Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ISomeInterface>
. This would be where ISomeInterface is implemented by all your models and contains the properties that the master layout view uses. or
Ensure your custom models inherit from whichever class is used to strongly type the master layout view.
In most cases you will need your custom model to build upon the underlying existing PublishedContent model for the page. This can be achieved by making your custom model inherit from a special base class called PublishedContentWrapped
:
PublishedContentWrapped
will take care of populating all the usual underlying Umbraco properties and means the @Model.
syntax will continue to work in the layouts used by your template.
Using Modelsbuilder you will find that all the generated models have a constructor that takes an IPublishedContent item in a similar way:
The models generated by Modelsbuilder are created as partial classes so it's possible to extend them by adding your own partial classes with matching signature.
We can now populate our custom view model in our controller and use the values from the custom model in our template view:
and in our template
You can also pass values directly into the controller action using the query string.
The values in the querystring
will be bound to the matching parameters defined in the controller's action:
For example:
To wire up a concrete instance of IMadeUpProductService, use a composer:
RenderController
You can replace Umbraco's default implementation of RenderController with your own custom controller for all MVC requests. This is possible by assigning your own default controller type in the Umbraco setup during initialization.
You can achieve this by updating the options for UmbracoRenderingDefaultsOptions
in the ConfigureServices
method in the Startup.cs
class.
First of all, you have to create your own controller. Your custom implementation of RenderController should either inherit from the core RenderController
as in the examples above or implement the IRenderController
interface.
Implement the IRenderController
:
Or inherit from RenderController
The last step is to configure Umbraco to use your implementation. You can do that in the ConfigureServices
method in the Startup.cs
class.
Setting up your own controllers and routes that exist alongside the Umbraco pipeline.
Documentation about how to setup your own custom controllers and routes that need to exist alongside the Umbraco pipeline
There's two places you can specify your routing, depending on whether it's in the context of a package, or your own site. If it's your own site you can do it in the Configure
method of Startup.cs
within the WithEndpoints
method call like so:
If you're creating a package you won't have access to the Startup.cs
file, so instead you must use a composer, for an example of this, see the example below.
Umbraco doesn't interfere with any user defined routes that you wish to have. Your custom routes to your own custom controllers will work perfectly and seamlessly alongside Umbraco's routes.
For a request to be considered executing in an Umbraco context, and therefore the Umbraco pipeline, it needs to have an HTTP request feature with the type UmbracoRouteValues
, all the information required for Umbraco to handle the request is stored there. The question is now, how do we add this request feature? There's three possibilities:
Do it manually - This requires that you have a custom route, controller, even middleware, and manually assign the UmbracoRouteValues
as an HTTP request feature, however you see fit. To create an UmbracoRouteValues
object generally requires: IUmbracoContextAccessor
(to access the CleanedUmbracoUrl
), IPublishedRouter
(to create the IPublishedRequestBuilder
), IPublishedRequestBuilder
(to set the published content and to build the IPublishedRequest
), IPublishedRequest
to assign to the UmbracoRouteValues
. As you can see this is a lot of work, but luckily there's some much easier ways.
Route a custom controller that implements the IVirtualPageController
interface, assigning the UmbracoRouteValues
to the HTTP requests will then be taken care of for you.
Route a custom controller with conventional routing, using the typical call to endpoints.MapControllerRoute
, and then call .ForUmbracoPage()
with an action for finding content on what MapControllerRoute
returns, now UmbracoRouteValues
will automatically be applied to any request to that controller.
Don't fret if this all seems a bit overwhelming, we'll be going through an example of the last two options.
As mentioned, with this approach we need to implement the IVirtualPageController
interface, this interface only has one method FindContent
which accepts an ActionExecutingContext
:
It can also be helpful to inherit from the UmbracoPageController
since this includes some useful helper methods such as CurrentPage
, do however note that it is not possible to inherit from RenderController
when doing custom routes like this.
Let's create a shop controller, with an Index action showing all our products. We will also add a Product action showing custom data about the product that could exists outside Umbraco. A common approach in a scenario like this is to have a "real" Umbraco node as a starting point. In this example we will use an empty "Products" Document Type with a list view, and "Product" Document Type containing a Stock-Keeping Unit (SKU). We also need some content based on those document types, a "Products" content node, which contains two product nodes, each with their own SKU.
After that bit of setup we can go ahead and create our shop controller which inherits from UmbracoPageController
and implements IVirtualPageController
, it'll look like this:
Now you'll see that FindContent
is complaining because we're not returning anything yet, but let's start by creating our to action methods that FindContent
will find content for.
First off we have the Index method:
With this method we return the view with the content found by the FindContent
method. This can then be used to list all the children in the view with Model.Children
.
Next we have our Product method:
This method is a bit more interesting, here we get some extra data from a different source, in this case a DbContext
, but this can be anything you want, using the id we get from the route values. We use this extra data to create a custom model, wich includes the available stores, which we then render the view with.
It's important to note that this custom model must implement IPublishedContent
, to do this we inherit from the ContentModel
class, in this case our model looks like this:
What's great about this is that we can use this model as a type argument when inheriting from UmbracoViewPage
in our model like so:
Which makes the model typed, so we can access the available stores like so:
But let's get back to our controller, the last thing we need now is to implement FindContent
method so we can find content for our actions and serve it to them. First we need to be able to get our content, and properties, so we need to inject IUmbracoContextAccessor
and IPublishedValueFallback
and save them to some fields like so:
Now that we have our dependencies, and our action methods, we're finally ready to implement the FindContent
method:
We start off by getting our product root using the UmbracoContext
to get it based off its id. Next we need to figure out what action is being requested. To do this we cast the actionExecutingContext.ActionDescriptor
to a ControllerActionDescriptor
and use its ActionName
propperty. If the action name is index, we return the product root. If it's product, we try to get the SKU from the route value id
. Then we try to find the child node which matches the SKU and return that.
There's only one last thing to do. We need to register our shop controller. If you're creating a controller for your own site you can do it in the Configure
method of Startup.cs
like so:
As you can see there's nothing Umbraco specific abouth the controller routing, it's using the default MapController
route of the EndpointRouteBuilder
, we give our mapping a name, a pattern for the controller and some default values, so if no action is specified it will default to Index
.
If you're creating a package you won't have access to the Startup.cs
, so instead you can use a composer with an UmbracoPipelineFilter
like so:
With that we have our controller with a custom route within an Umbraco context.
If the endpoint of your custom route is considered a client-side request e.g. /sitemap.xml, you will need to make a few changes to get this to work.
Define your route as before, specifying the correct client type route:
You will need to configure your route request options within your Startup.cs class. For single routes:
Or it can handle multiple routes:
In your FindContent method you should still be able to access and use IUmbracoContextAccessor through standard DI:
One of the benefits of the IVirtualPageController
is that it allows you to use attribute routing. If you wish to use attribute routing you must use an IVirtualPageController
and decorate your controller and/or actions with the Route
attribute. If we want to convert our above example into using attribute routing we must first add the attributes to our actions:
Now all we need to do is change our routing to use EndpointRouteBuilder.MapControllers();
instead of adding a specific route.
This will give us routing that's similar to what we have in the other example. It's worth noting that there's no defaults when using attribute routing, so to allow our index action to be accessed through both /shop
and /shop/index
, we add two attributes, specifying both routes individually.
Making a custom route within the Umbraco context using ForUmbracoPage
is similar to using IVirtualPageController
. The main difference is that with ForUmbracoPage
we no longer find the content from within the controller. Instead we assign the FindContent
method when routing the controller. One important thing about ForUmbracoPage
is that attribute routing is not available. To make our example from above work with ForUmbracoPage
, we want to remove any attribute routing, and no longer implement IVirtualPageController
. We'll also remove the FindContent
method, our controller will then end up looking like this:
As you can see we still inherit from UmbracoPageController
to get access to the helper method CurrentPage
, but the rest is a normal controller.
The Umbraco magic will now instead happen where we route the controller, here we will pass a Func<ActionExecutingContext, IPublishedContent>
delegate to the ForUmbracoPage
method, this delegate is then responsible for finding the content, for instance using a composer with the same logic as in the IVirtualPageController
it will look like this:
The Compose
method of our composer is much the same as any other normal routing. The one difference is that we call ForUmbracoPage
on the MapControllerRoute
where we pass in our FindContent
method. The FindContent
method is almost the same as it was in the controller in the IVirtualPageController
example, with one important difference. Since we can no longer inject our required service into the constructor, we instead request them using actionExecutingContext.HttpContext.RequestServices.GetRequiredService
. You should not save the HttpContext
or the IServiceProvider
you get from the actionExecutingContext
to a field or property on the class. The reason for this is that they will be specific to each request.
With this we have a custom routed controller within the Umbraco pipeline. If you navigate to /shop
or /shop/product/<SKU>
you will see the controllers actions being called with the content found in FindContent
.zspo
Umbraco automatically configures all required middleware in the WithMiddleware()
method in a specific order based on the .
PrePipeline
- executed before any Umbraco-specific middleware is added, an example can be .
PreRouting
- executed after the static files middleware and before the is added (using UseRouting()
). It can also be used to change the incoming URL.
PostRouting
- executed after the routing middleware is added and can be used to .
Injecting services into your controller constructors is possible with Umbraco's underlying dependency injection implementation. See for more info on this.
See for further information.
There is currently a bug in all versions below 9.5, where this fix won't work for mapping a client-side request to an Umbraco Controller. See for more details. v9.5 fixes this issue and it's recommended to update to the latest version!
URL redirect management in Umbraco
Whenever a document is published, and this causes changes to its URL (and any of its descendants' URLs), Umbraco makes a note of the old URLs. Whenever an incoming request is served and the default content finders cannot find a matching published document, Umbraco checks whether the URL matches one of these saved URLs. If a match is found, Umbraco returns a "301 Redirect" response pointing to the new URL of the document.
The URL Redirect Management functionality does not support rewriting "rules" (e.g. regular expressions), nor complex scenarios (e.g. changing the culture and hostnames configuration). There are already powerful solutions to deal with these types of situations, such as Microsoft's own Url Rewrite module for IIS. Since netcore is decoupled from the webserver hosting it, your approach for URL rewriting, outside what Umbraco provide out of the box, will depend on what you use to host your solutions, but for more info on the IIS Url Rewrite module have a look at the official documentation.
It is possible to list the redirect URLs via the Redirect Url Management dashboard in the Content section. This dashboard lists the original URL, new URL, and culture. It also allows you to delete a URL redirect.
In addition, the dashboard can be used to disable or enable the 301 Redirect Management (via the appsettings.json
configuration option described below - note that this requires an application restart to take effect).
Anytime a document is published and its corresponding url segment changes, Umbraco checks its URL (and all its descendants' URLs) for changes. For every URL that has changed, it creates (or updates) a row in the umbracoRedirectUrl
table. Rows in this table contain: the old url, the create date, and the target content identifier, culture, and a url hash.
Umbraco registers a new content finder, ContentFinderByRedirectUrl
, which runs as a normal content finder after the other content finders. It looks for the incoming URL in the database table and, if found, computes the URL of the target document and returns a "301 Redirect". These redirects are considered "permanent". It's good to note that we explicitly set no-cache
headers on these redirects so that when they change, browsers update the URL immediately. They are a "true" 301, however, and search engines will accept them as such.
The 301 Redirect Management feature is enabled by default.
It is possible to disable the feature entirely (both generating URLs in the database table, and running the content finder) by editing the appsettings.json
file:
See the web routing config reference for more configuration options
Describes special property type aliases which can be used to customise routing
There are a few special/reserved Umbraco Property Type aliases that can be used which can manipulate how the standard Umbraco routing pipeline works. You can add these Property Types to any Document Type and if values are assigned to these properties, Umbraco will adjust its routing accordingly. See below for full details.
Creating a property alias with this name and using a Content Picker property editor lets you create a 302 temporary redirect. This in effect means that when a user navigates to this node, they will be redirected away from it.
Add this property alias to your Document Type with a Content Picker property editor and Umbraco will load the selected page’s content transparently without performing any URL redirection. This essentially performs a rewrite.
This property when created as a text string lets you provide a different URL name to what is created by default by the name of the node. If you enter a value for this property and save/publish the content node you will see that its main URL is updated with a new path suffix.
This property when created as a text string lets you provide a comma separated list of alternate full URL paths for the node. For example, if your URL was /some-category/some-page/content-node, by adding an umbracoUrlAlias of "flowers", a user can navigate to the node by going to /flowers. The URL alias remains in the browser address bar as a 'mask' over the real URL. You can also specify paths like "flowers/roses/red".
With the release of Umbraco 9 and the change of the underlying web framework that is decoupled from the webserver, the way that you configure rewrites has changed as well.
Instead of the URL Rewriting extension in IIS you can use the URL Rewriting Middleware in ASP.NET Core, which needs to be added to your project startup code first.
If you are running Umbraco 9 on IIS you can still add a web.config
file to configure IIS features such as URL rewrites.
Make sure to check the official URL Rewriting Middleware in ASP.NET Core documentation for more information about when you should or should not use the URL Rewriting Middleware.
To use rewrites with Umbraco 9 you have to register the middleware in your Startup.cs
by using the UseRewriter
extension method and then configure the rewrite options.
Create an IISUrlRewrite.xml
file in the root of your project (next to your Startup.cs
file) containing:
In the Startup.cs
file you can add the URL Rewriting Middleware just before the call to app.UseUmbraco()
and use AddIISUrlRewrite
) to add the rewrite rules from the XML file:
On Linux, make sure to place the app.UseStaticFiles()
after the app.UseUmbraco()
statements for the redirect to work as intended.
In your csproj file add the XML file to a new item group and set CopyToOutputDirectory
to Always
:
On Umbraco Cloud the item group needs to be set to <CopyToPublishDirectory>Always</CopyToPublishDirectory>
for the file to be published to your deployed site.
RewriteOptions
has a number of "shortcut" methods to implement commonly used rewrites including:
AddRedirectToNonWww()
AddRedirectToWww()
AddRedirectToNonWwwPermanent()
AddRedirectToWwwPermanent()
AddRedirectToHttps()
For more details and other examples, take a look at the URL Rewriting Middleware in ASP.NET Core and RewriteOptions Class documentation.
A great site showing 10 very handy IIS Rewrite rules: URL rewriting tips and tricks
Another site showing some handy examples of IIS Rewrite rules: Some useful IIS rewrite rules
If you needed to a lot of static rewrites using rewrite maps: Rule with rewrite map rule template
For example, to always remove a trailing slash from the URL (make sure Umbraco doesn't add a trailing slash to all generated URLs by setting AddTrailingSlash
to false
in your RequestHandler settings):
Another example would be to enforce HTTPS only on your site:
Another example would be to redirect from non-www to www (except for the Umbraco Cloud project hostname):
If you use Umbraco Cloud check the Rewrite Rules article.
What the Umbraco Request Pipeline is
This section describes what the Umbraco Request Pipeline is. It explains how Umbraco matches a document to a given request and how it generates a URL for a document.
The request pipeline is the process of building up the URL for a node and resolving a request to a specified node. It ensures that the right content is sent back.
The followed method is called on the "PublishedContentRequest.PrepareRequest()" method: FindPublishedContentAndTemplate()
. We discuss shortly what this method is doing:
FindPublishedContent ()
Handles redirects
HandlePublishedContent()
FindTemplate()
FollowExternalRedirect()
HandleWildcardDomains()
No content?
Run the LastChanceFinder
Is an IContentFinder, resolved by ContentLastChanceFinderResolver
By default, is null (= ugly 404)
Follow internal redirects
Take care of infinite loops
Ensure user has access to published content
Else redirect to login or access denied published content
Loop while there is no content
Take care of infinite loops
Use altTemplate if
Initial content
Internal redirect content, and InternalRedirectPreservesTemplate is true
No alternate template?
Use the current template if one has already been selected
Else use the template specified for the content, if any
Alternate template?
Use the alternate template, if any
Else use what’s already there: a template, else none
Alternate template is used only if displaying the intended content
Except for internal redirects
If you enable InternalRedirectPreservesTemplate
Which is false by default
Alternate template replaces whatever template the finder might have set
ContentFinderByNiceUrlAndTemplate
/path/to/page/template1?altTemplate=template2 template2
Alternate template does not falls back to the specified template for the content
/path/to/page?altTemplate=missing no template
Even if the page has a template
But preserves whatever template the finder might have set
/path/to/page/template1?altTemplate=missing template1
Content.GetPropertyValue("umbracoRedirect")
If it’s there, sets the published content request to redirect to the content
Will trigger an external (browser) redirect
Finds the deepest wildcard domain between
Domain root (or top)
Request’s published content
If found, updates the request’s culture accordingly
This implements separation between hostnames and cultures
Information about creating your own content finders
To create a custom content finder, with custom logic to find an Umbraco document based on a request, implement the IContentFinder interface:
and use either an Umbraco builder extension, or a composer to add it to it to the ContentFindersCollection
.
Umbraco runs all content finders in the collection 'in order', until one of the IContentFinders returns true. Once this occurs, the request is then handled by that finder, and no further IContentFinders are executed. Therefore the order in which ContentFinders are added to the ContentFinderCollection is important.
The ContentFinder can set the PublishedContent item for the request, or template or even execute a redirect.
This IContentFinders will find a document with id 1234, when the Url begins with /woot.
You either use an extension on the Umbraco builder or, a composer to access the ContentFinderCollection
to add and remove specific ContentFinders
First create the extension method:
Then invoke it in ConfigureServices
in the Startup.cs
file:
To set your own 404 finder create an IContentLastChanceFinder and set it as the ContentLastChanceFinder. (perhaps you have a multilingual site and need to find the appropriate 404 page in the correct language).
A IContentLastChanceFinder
will always return a 404 status code. This example creates a new implementation of the IContentLastChanceFinder
and gets the 404 page for the current language of the request.
You can configure Umbraco to use your own implementation in the ConfigureServices
method of the Startup
class in Startup.cs
:
When adding a custom IContentLastChanceFinder
to the pipeline any Error404Collection
-settings in appSettings.json
will be ignored.
The pipeline works bidirectional: and .
is the process of building up a URL for a requested node. is every request received by the web server and handled by Umbraco.
This section will describe the components that you can use to modify Umbraco's request pipeline: & IUrlProvider