Question

This is in index.cshtml.

<script>alert(window.location.href);</script>
<script 
  type="text/javascript" 
  src="~/Scripts/require.js" 
  data-main="App/main">
</script>

This fails when the URL lacks a trailing slash. This URL http://host/appname/ results in expected behaviour (the browser loads /appname/App/main.js) but the same URL without a trailing slash causes the browser to attempt to load this /App/main.js resulting in a 404 not found.

I tried framing it like this

<script>alert(window.location.href);</script>
<script 
  type="text/javascript" 
  src="~/Scripts/require.js" 
  data-main="@Url.Content("~/App/main")">
</script>

but this only makes the problem even more obvious; the browser continues to work when the trailing slash is present, but now it throws up a message dialog full of raw HTML when the trailing slash is absent.

Here are a couple of possible solutions:

  • Configure IIS to append the trailing slash before it gets to ASP.NET
  • Set up the MVC app to check for this early and redirect with a trailing slash

Having IIS do it is probably not the best plan. There is a high chance the configuration change will cause problems with other aspects of the system, especially for multi page (non-SPA) MVC applications. The REST habit of encoding parameters into URLs as though they were resource paths conventionally does not use a trailing slash.

One might argue that this notation adds nothing over conventional URL parameter encoding and violates the HTTP spec (not to mention greatly annoying yours truly) but there is considerable investment in this type of encoding and therefore server configuration is less than ideal as a solution.

Was it helpful?

Solution

To perform a "courtesy redirect" in an MVC application, open your main controller and update the Index action. In my case the app is a Durandal SPA app, so the main Index method looks like this:

public class DurandalController : Controller
{
  public ActionResult Index()
  {
    return View();
  }
}

We need to check the request and if necessary redirect. It ends up looking like this:

public class DurandalController : Controller
{
  public ActionResult Index()
  {
    var root = VirtualPathUtility.ToAbsolute("~/");
    if ((root != Request.ApplicationPath) && (Request.ApplicationPath == Request.Path))
      return Redirect(root + "#");
    else
      return View();
  }
}

Redirection only comes into play once in the session lifecycle of a SPA app because it is loaded from the server only once per session. Implemented like this it has no consequences for other controllers and the URLs that they handle.

OTHER TIPS

Thank you for your usefull post.

I don't know why but for me in some ASP application, Request.ApplicationPath and Request.Path are not strictly equals so I must ignore case.

So a small improvement could be :

var root = VirtualPathUtility.ToAbsolute("~/");
if ((!root.Equals(Request.ApplicationPath, System.StringComparison.CurrentCultureIgnoreCase))
    && (Request.ApplicationPath.Equals(Request.Path, System.StringComparison.CurrentCultureIgnoreCase)))
{
    return Redirect(root + "#");
}
else
{
    return View();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top