Search code examples
c#asp.net-core

What's the difference between HttpRequest.Path and HttpRequest.PathBase in ASP.NET Core?


As detailed here: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httprequest?view=aspnetcore-3.0, ASP.NET Core's HttpRequest class includes both Path and PathBase properties.

What's the difference between these two properties? What's each one used for? What's the meaning of PathBase? What's the significance of having both a Path and a PathBase?

I can't find any documentation detailing why it is as it is - any ideas?


Solution

  • In ASP.NET core, there is this concept known as the path base. The basic idea is quite easy to understand: the path base is considered to be a fixed prefix for the path of all the incoming requests to your web application. By default, the path base is considered to be the empty string.

    This means that, by default, when a request enters your application, all the path portion of the request's URL will be mapped to the Path property of the HttpRequest object and the PathBase property will be set to string.Empty.

    As an example, consider an ASP.NET core application running in your local machine and listening to port 3000. Suppose that you are running the application by using the raw kestrel web server (so there is no reverse proxy involved, requests arrive directly to kestrel).

    When you request the URL http://localhost:3000/foo/bar, then the HttpRequest object will have the following properties:

    • HttpRequest.Path will be set to /foo/bar
    • HttpRequest.PathBase will be set to string.Empty

    You will get the same situation when you decide to host your application on Azure by using a Windows app service.

    In this hosting scenario, the default for an ASP.NET core web application is being executed inside the same process as the IIS worker process. This basically means that there is only one process involved. Again, there is no reverse proxy and the kestrel web server is not used at all: the request is handled by IIS directly. You can find some details here if you are interested).

    In that case, the public URL for your application will be something like https://my-application.azurewebsites.net. When you browse to the URL https://my-application.azurewebsites.net/foo/bar, the situation for the incoming http request will be the following:

    • HttpRequest.Path will be set to /foo/bar
    • HttpRequest.PathBase will be set to string.Empty

    Again, as before, the path base is the empty string.

    There are different hosting scenarios where you may decide to expose your application by using a virtual directory.

    For instance, you may decide to host the ASP.NET core web application in your own datacenter by using a Windows virtual machine having IIS installed. In that case, you may have an existing web site in IIS and want to create a virtual application having a proper alias under that web site. Again, in this scenario, there is no reverse proxy involved and the kestrel web server is not used at all, as explained above for the Azure Windows app service: the request is handled directly by the IIS worker process (in the process hosting model).

    Suppose that the public URL of your web site is https://sample-application.contoso.net and that you have chosen sample-alias as the alias for the virtual application. This implies that all the requests to your ASP.NET core web application will have a path portion starting with sample-alias. For instance, when you want to require the home page of your application, you will browse to https://sample-application.contoso.net/sample-alias.

    In this case when you request the URL https://sample-application.contoso.net/sample-alias/foo/bar, the HttpRequest object in your application will be done in the following manner:

    • HttpRequest.Path will be set to /foo/bar
    • HttpRequest.PathBase will be set to /sample-alias

    Due to the way the default web host for an ASP.NET core application is built, this scenario involving IIS virtual applications works out of the box. The middleware pipeline is aware of the common prefix to all the incoming HTTP requests, and it is able to set the path base to /sample-alias and the path property to the remaining part of the incoming request's path (/foo/bar in my example above).

    As a rule of thumb, you can consider that an ASP.NET core web application works fine without any additional configurations when you want to host it by using IIS. This is true for the path base property, too. Check here to verify that the request base path is set automatically inside your application at the startup.

    As a last example, consider hosting your application on a Linux machine, by using nginx as a reverse proxy. In this case, your application will be executed inside the kestrel web server, but it won't be directly exposed to the public internet. The thing being exposed to the public internet is the nginx web server, which routes the incoming HTTP requests to the kestrel web server (where your application is executed). You may decide to configure your nginx so that all requests starting by the prefix /awesome-application will be routed to your ASP.NET core web application.

    As an example, suppose you expose nginx to the public internet at the URL https://ingress.contoso.net. In this case, if you want to request the home page of your application, you need to browse to https://ingress.contoso.net/awesome-application/.

    In this case, you can't get the awesome-application request path base for free. By default, kestrel is not aware of it and it considers the request path base to be string.Empty.

    In order to make kestrel aware of the request path base, you need to use UsePathBaseMiddleware as the first item in your middleware pipeline.

    If you need more details for this case, follow this documentation and also see this stackoverflow question.