Getting the URL Path in ASP.NET Core

Recently our team ran into a problem with getting the URL path in an ASP.NET Core MVC project. We were getting different results running locally versus deployed to our QA environment. Enter `HttpRequest.PathBase`.

Recently our team ran into a problem with getting the URL path in an ASP.NET Core MVC project. In this particular scenario we needed to get the currently requested URL, strip a key/value pair from the query string, and return that URL, but we got different results running locally versus deployed to our QA environment.

Our method looked something like this:

public string GetModifiedUrl(HttpRequest request, string key) 
{
    NameValueCollection qs = HttpUtility.ParseQueryString(request.QueryString.ToString());
    qs.Remove(key);
    string url = request.Path + "?" + qs;
    return url;
}

This worked fine running locally, but broke once we deployed to our QA environment. We have production and QA domains, and our applications are deployed to IIS as subfolders on each domain, qa.domain.com/app1, for example.

The problem with the above code is that the HttpRequest.Path property is not the URL path. I thought it would be equivalent to JavaScript’s Location.pathname, a “string containing an initial '/' followed by the path of the URL, not including the query string or fragment” (Location, MDN Web Docs).

The documentation describes HttpRequest.Path as the “portion of the request path that identifies the requested resource” and notes the “value may be Empty if PathBase contains the full path, or for 'OPTIONS *' requests” (HttpRequest Class, Microsoft Learn). So ASP.NET Core may split the URL path into the PathBase and Path properties, and that’s exactly what happens in our hosting environment.

For our hosting setup as applications on a single domain on IIS, ASP.NET Core puts that first, containg subfolder as the HttpRequest.PathBase. Running locally, that property is an empty string, but in our QA and Prod developments, for a site deployed as qa.domain.com/app1, it would be "app1".

Fixing our method means changing the url concatenation to start with HttpRequest.PathBase:

  public string GetModifiedUrl(HttpRequest request, string key) 
  {
      NameValueCollection qs = HttpUtility.ParseQueryString(request.QueryString.ToString());
      qs.Remove(key);
-     string url = request.Path + "?" + qs;
+     string url = request.PathBase + request.Path + "?" + qs;
      return url;
  }