javascriptasp.net-mvc

How to write a relative path for fetch() that works when my site is deployed in subdirectories?


Context

I'm building a web application using ASP.NET MVC, and I need to use the fetch() API to send data from the front-end to a controller action. The tricky part is ensuring that the fetch() path works correctly when the app is deployed under different base URLs.

For example, the app might be hosted at:

Problem

If I use a path like this:

fetch("/Home/Data")
  .then(response => response.json())
  .then(data => console.log(data));

It works fine on localhost. But when deployed to a subdirectory like https://www.example.com/MyApp/ or https://www.example.com/qa/MyApp/, it tries to fetch from https://www.example.com/Home/Data — which is incorrect.

Question

How can I write the fetch() call so that it works correctly regardless of the base path the app is deployed under?

I need a way to make the path dynamic or relative to the current folder in ASP.NET MVC apps.


Solution

  • I assume you're trying to send data from front-end to controller action using .NET MVC using Razor Page (.cshtml) or a static .js file.

    The Issue

    When deploying an .NET MVC application under a subfolder like /MyApp/ or /qa/MyApp/, using fetch('/Home/Data') in a fetch() call will try to fetch from the root of the domain instead of the respecting application base path, which is https://www.example.com/Home/Data.

    Solutions (Static JS-only)

    You can use this pattern to construct a safe base path:

    const base = window.location.pathname.replace(/\/[^/]*$/, '/');
    fetch(base + "Home/Data")
      .then(response => response.json())
      .then(data => console.log(data));
    

    This method helps you to trim the current path to the base folder and appends your controller/action path relative to it.

    Alternative: Use new URL()

    Similarly, you can also use the URL constructor to create a relative path safely, but you must ensure you include a trailing slash at the end of the base URL like this:

    const base = new URL('Home/Data', window.location.href + '/');
    fetch(base)
      .then(response => response.json())
      .then(data => console.log(data));
    

    Notes: By adding a trailing slash(/) to window.location.href, the browser will correctly interprets the base as a folder rather than a file, preserving the base path like /qa/MyApp/. If you don't include the trailing slash (/), the base will be https://www.example.com/qa/Home/Data.

    Reference: MDN - URL() constructor

    Caution: Url.Action()

    Using Razor helpers like @Url.Action('Data', 'Home') only works inside .cshtml views. It won't work if you're using static .js files.