This can be done with URL Rewrite
<rule name="Add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>
I did it by adding this to my global asax.cs file:
protected void Application_BeginRequest(Object sender, EventArgs e) { if (HttpContext.Current.Request.Url.AbsolutePath != "/" && !HttpContext.Current.Request.Url.AbsolutePath.EndsWith("/")) { string redirect = HttpContext.Current.Request.Url.AbsolutePath; redirect = redirect + "/"; Response.Clear(); Response.Status = "301 Moved Permanently"; Response.AddHeader("Location", redirect); Response.End(); }
UPDATE: Doing it via the webconfig is better so we don't redirect .css URLs or .jpg URLs.
thanks for your reply Quan Mai
Used your method and it works great on the front end, but the issue is it breaks the episerver back end, how can I exclude all URLs assosiated with the back office?
You should be able to do that by adding this rule before the previous rule, assuming /episerver is your admin path
<rule name="block" stopProcessing="true"> <match url="^/episerver$"
ignoreCase="true" />
<action type="None" />
</rule>
I did try that but its still breaking the back office.... I posted a simlar question on stack overflow... I'll copy and paste it......
I want to create a URL rewite rule that adds a / on URLs that don't have one so for example:
www.domain.com/news/latest will get redirected to www.domain.com/news/latest/
The rule below does exactly that, but the problem I am having is two fold:
This rewrite rule is getting applied to things like image files. So For example domain.com/globalassets/icons/image.svg gets changed to domain.com/globalassets/icons/image.svg/ causing a 404 its not happening with CSS files which is strange, maybe because I am adding them using the RegisterBundles method in MVC?
This is a ASP.net MVC based website using a CMS (episerver) so I want to ignore any redirects in the Admin area so I added a second rule, but again its doing this to the CSS and images breaking the admin area.
This is what I have got so far, can anyone help me get this rule working correctly?
I just want this to work for the URL's to pages only and not effect the other supporting files like images and css, js files.
At the moment it looks like this....
<rewrite> <rules> <rule name="Exclude Slash Episerver " stopProcessing="true"> <match url="^episerver/" /> <action type="None" /> </rule> <rule name="Add trailing slash" stopProcessing="true"> <match url="(.*[^/])$" /> <conditions> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Redirect" redirectType="Permanent" url="{R:1}/" /> </rule> </rules> </rewrite>
[Pasting files is not allowed][Pasting files is not allowed][Pasting files is not allowed]
I dont' think this is correct, did you try with ^/episerver$ instead?
<match url="^episervers/" />
Yeah I did try that first (going to try it again now) but it didn't work... is $ a wild card? so it catches anything with /episerver/matchesAnyThingAfterTheSlash ?
Hmm. $ is the end of the regex. This works for me on Quicksilver
<rule name="add trailing slash" stopProcessing="true">
<match url="(.*[^/])$" ignoreCase="true"/>
<conditions>
<add input="{URL}" pattern="^/(Login|episerver|util)" negate="true"/>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>
So it's a bit different way, but same purpose. Login is optional, while episerver|util is required
I think the addition of the "util" part of the pattern is the key piece there Quan :)
For future visitors, I wrote a blog post explaining the "magic" https://vimvq1987.com/adding-backslash-ending-to-your-urls-by-urlrewrite/
One more thing.... I just put this on to my staging server and we have a SSL certificate, now I am getting errors about mixed content, becuase some JS and CSS is now coming over http.... if I remove the rule it goes away....
Is there something I need to do to account for the fact I am using a SSL certificate.
There is a singelton instance of EPiServer.Web.Routing.RoutingOptions registered in IOC container. You can set the property UseTrailingSlash on the options class to control if you want the generated URL:s to have an trailing slash or not.
Hi Johan,
This looks like exactly what I need, I had no idea episerver had something like this built in out of the box.
BUT.... I can't get it to work. This is what I have got...I have added this to my app start method, but I am not getting the / at the end of the URLs, do I need an IIS redirect as well?
I Put a break point in this method and I can see that routingOptions.UseTrailingSlash is already set to true, but my Urls are a not being redirected to have the / on the end...
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); BundleConfig.RegisterBundles(BundleTable.Bundles); AutoMapperConfig.InitializeMappings(); var routingOptions = ServiceLocator.Current.GetInstance<RoutingOptions>(); routingOptions.UseTrailingSlash = true; }
any ideas.... any one?
I was probably a bit unclear, setting UseTrailingSlash will not do any redirection it will only assure that generated urls contain a trailing slash (then hopefully there will not be that common there will be request wwithout a trailing slash)
Also the recommended way to set options is to use Configure method in a IConfigurableModule like:
public void ConfigureContainer(ServiceConfigurationContext context) { context.Services.Configure<RoutingOptions>(o => o.UseTrailingSlash = true); }
OK, so the only way to do it so there is a redirection is by a URL re-write?
The issue I am having is with SSL...
When I use the rule below, it works on my Local Machine....but when I put it on the staging server I get this error,
Mixed Content: The page at 'https://www.bit.truphone.com/uk/iot-solutions/' was loaded over HTTPS, but requested an insecure stylesheet
and the CSS gets blocked.
<rules> <rule name="add trailing slash" stopProcessing="true"> <match url="(.*[^/])$" ignoreCase="true"/> <conditions> <add input="{URL}" pattern="^/(Login|episerver|util|App_Themes)" negate="true"/> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Redirect" redirectType="Permanent" url="{R:1}/" /> </rule>
If you prefer then you can do the redirection in code instead of in config, like below that attaches an eventhandler to IContentRouteEvents in a IInitializableModule:
public void Initialize(InitializationEngine context) { context.Locate.Advanced.GetInstance<IContentRouteEvents>().RoutedContent += (s, args) => { var currentPath = args.RoutingSegmentContext.RequestUrl.AbsolutePath; if (!currentPath.EndsWith("/") && string.IsNullOrEmpty(VirtualPathUtility.GetExtension(currentPath))) args.RoutingSegmentContext.PermanentRedirect(VirtualPathUtility.AppendTrailingSlash(args.RoutingSegmentContext.RequestUrl.ToString())); }; }
I tried to do in code before with this...
protected void Application_BeginRequest(Object sender, EventArgs e) { if (HttpContext.Current.Request.Url.AbsolutePath != "/" && !HttpContext.Current.Request.Url.AbsolutePath.EndsWith("/")) { string redirect = HttpContext.Current.Request.Url.AbsolutePath; redirect = redirect + "/"; Response.Clear(); Response.Status = "301 Moved Permanently"; Response.AddHeader("Location", redirect); Response.End(); }
but the problem I have is everything over http gets this redirect so image URLS /path/path/image.jpg gets redirected to /path/path/image.jpg/ and that gets a 404
This is starting to drive me nuts... there must be a way! :-)
Thank you, thank you thank you.
Doing it in code works, I had a look at your code and I get it now.... this URL redirect only applies to Routed Content that comes from episerver. THANK YOU... works in the staging server too with no SSL problems!
THANK YOU!
Just in case someone else finds this post, here is a quick update. I had to modify the code from Johan, to exclude the back office episerver paths, if you don't do this it will break things like thumbnail previews:
context.Locate.Advanced.GetInstance<IContentRouteEvents>().RoutedContent += (s, args) => { var currentPath = args.RoutingSegmentContext.RequestUrl.AbsolutePath.ToLower(); if (!currentPath.EndsWith("/") && !currentPath.Contains("episerver") && !currentPath.Contains("util") && !currentPath.Contains("App_Themes") && string.IsNullOrEmpty(VirtualPathUtility.GetExtension(currentPath))) args.RoutingSegmentContext.PermanentRedirect(VirtualPathUtility.AppendTrailingSlash(args.RoutingSegmentContext.RequestUrl.ToString())); };
there are lot more things to be aware of that don't need trailign slahes :) like signalr hubs is one of the first that came to my mind.
Hi guys, in the end this is the code that works! it's doing the redicrect on all URLs that don't have the / apart from any paths that are related to Episerver
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))] [InitializableModule] public class TrailingSlash : IInitializableModule { public void Initialize(InitializationEngine context) { context.Locate.Advanced.GetInstance<IContentRouteEvents>().RoutedContent += (s, args) => { var currentPath = args.RoutingSegmentContext.RequestUrl.AbsolutePath.ToLower(); if (!currentPath.EndsWith("/") && !currentPath.Contains("episerver") && !currentPath.Contains("util") && !currentPath.EndsWith("App_Themes") && string.IsNullOrEmpty(VirtualPathUtility.GetExtension(currentPath))) args.RoutingSegmentContext.PermanentRedirect(VirtualPathUtility.AppendTrailingSlash(args.RoutingSegmentContext.RequestUrl.ToString())); }; } }
BUT..... when redirection happens this is what it does
A. https://www.mywebsite.com/uk/products (301)
B. http://www.mywebsite.com/uk/products/ (301)
C. https://www.myserbsite.com/uk/products/ (200)
Is there a way to make it just go from A to C without going to B?
Is there a way to configure episerver so that all my URLs end with slash.
So for example if a user navigates to www.mywebsite.com/en/home they are redirected to www.mywebsite.com/en/home/
Thanks in advance.
Ayo