ASP.NET Core ContentRoot and WebRoot Simplified

What is a ContentRoot and a WebRoot, what's the difference between these two? and when to use these? Let's find out in this article.

When you are building applications with .NET Core, you might have already observed that there are two kinds of paths to configure – ContentRootPath and WebRootPath.

You can also notice these two properties, particularly when building your host, and they point to two different locations (although inside the same base path)

For example, the below code in .NET 6 when executed prints two different base paths –

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

WebApplication app = builder.Build();

Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}");
Console.WriteLine($"WebRootPath: {builder.Environment.WebRootPath}");

app.Run();
ContentRoot Path: D:\Dotnet Core Projects\SomeTestApp\
WebRootPath: D:\Dotnet Core Projects\SomeTestApp\wwwroot

So what is a ContentRootPath and a WebRootPath, what’s the difference between these two? and when to use these? Let’s find out in this article.

What is a ContentRootPath?

Although ContentRootPath sounds something like related to content, it is actually the base path at which the application runs, it is where the runtime looks up for the executables, the libraries and so on.

The content root path provides the base path for:

  • Executables hosting the application (the application .exe file)
  • compiled assemblies that help make and run the application (assemblies and other .dll files associated with the application)
  • files used by the application such as –
    • cshtml / razor files
    • configuration files (.json / .XML)
    • data files (.db)
    • Web root (wwwroot folder)

Basically, the ContentRootPath is set to the path at which the application is being executed – although we can also set our own custom path while building the Host, as below in .NET 6 –

WebApplicationBuilder builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    ContentRootPath = Directory.GetCurrentDirectory()
});

WebApplication app = builder.Build();

Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}");
Console.WriteLine($"WebRootPath: {builder.Environment.WebRootPath}");

app.Run();

Or the good old .NET Core 3.x or .NET 5 way –

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                    webBuilder.UseStartup<Startup>();
                });

ContentRootPath is where the Host looks for the executables and assemblies to run. by default it is the current directory when the application is run


What is a WebRootPath?

WebRootPath on the other hand, is related to the static assets and files that the application – specifically web application uses.

  • The web root path provides the base path for all the static files used by the application such ass CSS stylesheets, JS scripts or Images
  • By default the static files are stored only in web root directory (wwwroot) and its sub directories
  • If you specify ~/ path inside cshtml or razor files, it points to relative path inside the Web Root

Similar lo ContentRootPath, you can configure a custom path for your Web Root as below in .NET 6 –

WebApplicationBuilder builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    ContentRootPath = Directory.GetCurrentDirectory(),
    WebRootPath = "wwwroot"
});

WebApplication app = builder.Build();

Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}");
Console.WriteLine($"WebRootPath: {builder.Environment.WebRootPath}");

app.Run();

Or Or the good old .NET Core 3.x or .NET 5 way –

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                    webBuilder.UseWebRoot("wwwroot");
                    webBuilder.UseStartup<Startup>();
                });

On top of setting the WebRootPath, we can also specify any custom path to serve static files (basically what the WebRoot does) through the Static Files middleware (app.UseStaticFiles()) within our application.

All the directories and sub-directories present in the WebRootPath will be copied over, when we publish our application.

On the other hand, we can prevent a sub-directory to be copied over while publishing, by specifying the path within a <Content /> tag in our csproj.

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

WebRootPath is the base path for all the static files served by the application, such as CSS, JavaScript or Image files. It is actually a sub path of the ContentRootPath.


Conclusion

Both the ContentRootPath and the WebRootPath serve two different purposes in an ASP.NET Core application. This distinction is even more visible, when we’re dealing with a Web Application that has static files to serve.

The ContentRoot is the base path where the application executes, this is generally the execution directory while debugging or when published.

The WebRoot is the base path for all the static files that reside in the web application, it is a relative path which defaults to wwwroot folder, and is relative to the ContentRoot.

TL;DR – Here’s a comparison

ContentRootWebRoot
Executables hosting the application (the application .exe file)all the static files used by the application – css/js/images
compiled assemblies that help make and run the application (assemblies and other .dll files associated with the application)By default the static files are stored only in web root directory and it’s sub directories
files used by the application such as –
• cshtml / razor files
• configuration files (.json / .XML)
• data files (.db)
• Web root (wwwroot folder)
The ~/ path inside cshtml or razor files points to path inside wwwroot, it’s called Virtual Path
We can specify a different root while building the host (SetBasePath() or UseContentRoot())We can specify a different root while building the host (UseWebRoot()), or by configuring the UseStaticFiles() middleware.
We can also prevent publishing any assets inside the Web Root, via the tag inside the csproj

What do you think? Write down your thoughts below!

Reference: Fundamentals – Generic Host in ASP.NET Core

Default image
Sriram Mannava

I'm a full-stack developer and a software enthusiast who likes to play around with cloud and tech stack out of curiosity.

2 Comments

Leave a Reply