SaaS CMS has officially launched! Learn more now.

Custom route messes up assets URL



We have come across an issue with custom routes messing up the assets path when using SiteAssets for images etc. Usually you would get a URL for say an image located in the SiteAssets of a website that looks like this: but we get The image works and all so it took forever before we even noticed it. GlobalAssets works fine.

I´ve narrowed it down (with help from Episerver Developer Support) to a custom route that looks like this as the root cause:

var defaults = new { controller = "ListPage", page = 1, query = UrlParameter.Optional, tags = UrlParameter.Optional, sortorder = UrlParameter.Optional, action = "index" };
var defaultMapContentRouteParameters = new MapContentRouteParameters
	RouteHandler = new RouteHandler(
ServiceLocator.Current.GetInstance(),ServiceLocator.Current.GetInstance(),ServiceLocator.Current.GetInstance(),ServiceLocator.Current.GetInstance(),						ServiceLocator.Current.GetInstance(),

routes.MapContentRoute("listRoute", "{language}/{node}/{page}/{tags}/{query}/{sortorder}", defaults, defaultMapContentRouteParameters);

If I remove this route then all my images and so on gets siteassets in the URL again. We have setup this custom route because we have listing pages of different types (News, Press releases etc.) and we want to be able to search on the page for items using pageId, freetext, tags, sortorder that will be sent to the controller and action Index like parameters.

Can we rewrite this custom route in any way it still works like we want but it doesn´t mess up the URL for SiteAssets?

Anyone that has stumbled onto this?

Jun 02, 2016 20:54

Since you have default values for all custom segments {page}, {tags}, {query}, {sortorder} then will that custom route handle request that does not contain those segments (using the default values). If you make some segment mandatory then it will not  interfer when that value is not present.

Another option if that route is only to be used form incoming route (that is that you never want the UrlResolver to create such outgoing links)  then you can set Direction on MapContentRouteParameters to SupportedDirection.Incoming

If none of the above is feasible then you could try to move the route registration so it gets called after the route serving site assets.

Jun 03, 2016 12:52

I´m not entirely sure on how to make some segments mandatory as you suggested, custom routing isn´t something that I´ve been working with that much :) I set the parameters to having a default value (query = "" etc) instead of UrlParameter.Optional as there was no UrlParameter.Mandatory, but that didn´t do any difference, it still messed upp the SiteAssets URL to SysSiteAssets. The SupportedDirection.Incoming however seemed to do the trick actually.

But please enlighten me how to set the parameters to be mandatory if I´m supposed to do it in any different way so I can test it correctly.


Jun 07, 2016 14:53

Just remove the entry from the default object. So for example

var defaults = new { controller = "ListPage", page = 1, query = UrlParameter.Optional, tags = UrlParameter.Optional, sortorder = UrlParameter.Optional, action = "index" };

specifies default values for controller, page, query, tags, sortorder and action. So for example remove the tags part above so you get
var defaults = new { controller = "ListPage", page = 1, query = UrlParameter.Optional, sortorder = UrlParameter.Optional, action = "index" };

then in your pattern "{language}/{node}/{page}/{tags}/{query}/{sortorder}" it means tags must be part of the url to match on incoming routing. And for outgoing url generation it means "tags" must be part of route values.

Edited, Jun 07, 2016 15:00

Putting route last in chain is usually a great idea to avoid breaking default routing of episerver. Highly recommended :)

Jun 07, 2016 22:07

Noted Daniel :) I know the order matters when you have several custom routes (first match first serve), but can I "force" my custom route(s) to be last in chain somehow?

Jun 08, 2016 8:02

I removed the parameters so it looked like this: 

var defaults = new { controller = "ListPage", action = "index" };

and the pattern looked like this:

routes.MapContentRoute("defaultRoute", "{language}/{node}", defaults, defaultMapContentRouteParameters);

But that made the whole custom route not work at all. I also left the page parameter and the page part in the pattern but that didn´t have any affect either.

So what actually worked is the SupportedDirection which is what we might go with as the UrlResolver doesn´t need to be able to create URLs with the parameters used.

Jun 08, 2016 10:18
 [ModuleDependency(typeof(EPiServer.Web.InitializationModule), typeof(StructureMapInitialization))]
    public class CustomRoutesModule : IConfigurableModule
        public void Initialize(InitializationEngine context)
            EPiServer.Global.RoutesRegistered += Global_RoutesRegistered;
        void Global_RoutesRegistered(object sender, RouteRegistrationEventArgs e)
            e.Routes.Add("custom301s", new SeoManagerRoute());

You can use the RoutesRegisteredEvent like above to add custom routes after the Episerver ones...I use it to add 301s for pages that Episerver can't route for instance. 

Jun 08, 2016 16:21
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.