Virtual Happy Hour this month, Jun 28, we'll be getting a sneak preview at our soon to launch SaaS CMS!

Try our conversational search powered by Generative AI!

Route - AppendTrailingSlashToVirtualPath usage and how to disable it?



I am having some trouble with EPiServer default route. I have a login page type in the CMS and a corresponding controller to serve the login page. 

Below is my view, the view contains two post forms, first form is rendered from controller directly, post form action just works fine. However the second form is rendered inside another view by using Html.Action, the post form action is completed wrong and also there is no trailing splash append after the action which cause route not match the incoming request.

e.g. the first form use the following code snippet

         @using (Html.BeginForm("Auth", "LoginPage", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { accept_charset = "utf-8" }))

    the form action is rendered as  "/signin/auth/?ReturnUrl=  (My login page name url in CMS is called signin, so I guess that's why when I Passed LoginPageController to the form, it is rendered as my real page name)

the second form use the Html.Action to render the partial view, the action is rendered as "/LoginPage/ExternalLogin?ReturnUrl=" (see here, there is no trailing slash and the controller name is translated to page name - signin like the first form)

@Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })

The ExternalLoginsList returns the following view

using (Html.BeginForm("ExternalLogin", "LoginPage", new { ReturnUrl = ViewBag.ReturnUrl }))
    <fieldset id="socialLoginList">
        <legend>Log in using another service</legend>
        @foreach (Microsoft.Web.WebPages.OAuth.AuthenticationClientData p in Model)
            <button type="submit" name="provider" value="@p.AuthenticationClient.ProviderName" title="Log in using your @p.DisplayName account">@p.DisplayName</button>


I am so confused about the inconsistent behaviour, can someone explain this to me?

May 19, 2013 15:27

Can someone confirm is it a bug or something I missed?

May 20, 2013 12:07

I can easily reproduce this issue in Alloy template.

If you use Html.BeginForm in the page, the form's action url is correct. However if it is inside another view and render using Html.Render, the form's action url is not parsed by route.

May 21, 2013 16:57

The child action request (caused by @Html.Action) will not go through "ordinary" routing, instead ASP.NET MVC will route the request directly to the controller. This means that values set on RouteData by EPiServer routing will not be present on child actions. 

More specifically in this case the "node" parameter (that indicates which content item the request is for) is missing.

What you can do is add the following to your partial view:

@using (Html.BeginForm("ExternalLogin", "LoginPage", new { ReturnUrl = ViewBag.ReturnUrl, node = ViewContext.RequestContext.GetContentLink() }))


May 22, 2013 14:38

Hi Johan

Thanks for taking a look of my issue. The solution you provide did partially solve my problem. The url was generated correctly if the partial view resides in the LoginPage view.

However I had another partial login area sitting on the layout page, it contains two links to link to "login" and "join" page, these two links's action are inside the "LoginPageController", when I used the same technique with Url.Action, it still generated /LoginPage/Index and /LoginPage/Join.

I get a bit frustrated of the episerver routing system. 

May 23, 2013 15:03

Hi Johan

Any solution yet?

May 25, 2013 10:24


Can you point me out how to make the Url.Action work in my situtation?


May 29, 2013 4:41

The reason it does not work is that in the CMS Route it will not try to resolve a VirtualPath if the controller in the route values differs from the controller for the main request. I have reported a bug for that either we should always try to resolve the virtual path or that it should be possible to control the behaviour by a parameter in route values.

But for now you can do a workaround by setting the controller on the main request temporary to the same as the sub controller, like:

var currentController = Html.ViewContext.RouteData.Values[RoutingConstants.ControllerKey];
Html.ViewContext.RouteData.Values[RoutingConstants.ControllerKey] = "Login";
@Url.Action("ExternalLogin", "Login", new { node = new ContentReference(17) });
Html.ViewContext.RouteData.Values[RoutingConstants.ControllerKey] = currentController;

May 29, 2013 13:47


new ContentReference(17) should be replaced with the reference to your login page.

May 29, 2013 13:50
This thread is locked and should be used for reference only. Please use the Episerver CMS 7 and earlier versions forum to open new discussions.
* 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.