13

I would like to be able to browse a directory in the web root (such as my \img directory or \pdf directory) from code within a controller.

I would like to use something like the following where env is an instance of IWebHostEnvironment:

var provider = env.WebRootFileProvider;
var path = env.WebRootPath;

I'm not sure how to get an instance of IWebHostEnvironment from within a controller. How can this be done?

Kirk Larkin
  • 84,915
  • 16
  • 214
  • 203
Intensivist
  • 767
  • 2
  • 7
  • 19
  • 4
    [Dependency injection...](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1) – DavidG Dec 12 '19 at 12:49
  • I tried creating a static of the env from the Configure in startup.cs. However, the WebRootPath is null. Is the root directory even accessible from a controller? – Intensivist Dec 12 '19 at 13:00
  • 2
    Don't do that, use dependency injection. If you don't know what that is, go research it now. – DavidG Dec 12 '19 at 13:04
  • I did use DI and still the WebRootPath and WebRootFuleProvider are null. I got rid of the static – Intensivist Dec 12 '19 at 13:07
  • 1
    That makes no sense, you would need to show us the code. – DavidG Dec 12 '19 at 13:12
  • It seems the same as [this question](https://stackoverflow.com/questions/43709657/how-to-get-root-directory-of-project-in-asp-net-core-directory-getcurrentdirect) – Franly Reynoso Dec 12 '19 at 13:20

2 Answers2

20

You can use dependency injection to inject an IWebHostEnvironment instance into your controller. Either in the constructor:

public class MyController : Controller
{
    private readonly IWebHostEnvironment _env;
    public MyController(IWebHostEnvironment env)
    {
        _env = env;
    }
}

or in any or the controller's method:

public class MyController : Controller
{
    [HttpGet]
    public IActionResult Me([FromServices] IWebHostEnvironment env)
    {
        return View();
    }
}

Note that the default WebRootFileProvider points to the wwwroot folder, so you need to ensure it exists, otherwise you'll get a NullFileProvider.

Métoule
  • 13,062
  • 2
  • 56
  • 84
  • This is precisely how I did it. I placed ":IWebHostEnvironment env" in the controller's constructor and assigned env to a private variable. I can confirm that env is in fact instantiated (not null) however the WebRootFileProvider is null as is WebRootPath. Interesting the that ContentRootPath and ContentRootFileProvider are not null and funtional. Why would I not have access to the WebRoot? – Intensivist Dec 12 '19 at 13:43
  • Note that I used `IHostingEnvironment`, not `IWebHostEnvironment`. – Métoule Dec 12 '19 at 14:03
  • I did notice that. I tried IHostingEnvironment too and both WebRootPath and WebRootFileProvider are null. Also, I get a warning that IHostingEnvironment will be deprecated and that it is recommended to use IWebHostEnvironment. Not sure why nulls. No additional code to provide, it's this: var provider = _env.WebRootFileProvider; var path = _env.WebRootPath; – Intensivist Dec 12 '19 at 14:19
  • Sorry, `IHostingEnvironment` is for ASP.NET Core 2. It's strange that `_env.WebRootFileProvider` is `null`.. – Métoule Dec 12 '19 at 15:44
  • I was never able to get WebRootPath or WebRootFileProvider to return anything other than null, even when passing the IWebHostEnvironment as DI in my controller's constructor (or the actual controller). Noteworthy, WebRootPath and WebRootFileProvider are null, even in the Configure() of Startup.cs. I'm not sure why. However, var p = new PhysicalFileProvider("C:\\");var contents = p.GetDirectoryContents("\\Data"); work within the controller. Not very elegant. I wish I could get the WebRoot... to be a non null value. For now, at least I have a way to get to the WebRoot. – Intensivist Dec 13 '19 at 00:17
  • That's extremely strange, it should be set when you create your `WebHost` in `Program.cs`. Can you share how you initialize the `WebHost`? Do you call `CreateDefaultBuilder`? – Métoule Dec 13 '19 at 08:13
  • To Repro: I am using VS 2019 and created an ASP.NET Core 3.1 API. There are no other modifications to the template that's created. I added a DI for IWebHostEnvironment in the constructor of the templated WeatherForecastController. Finally added "var p = _env.WebRootFileProvider" to the default [HttpGet]. Placed a debug break. It's always "Microsoft.Extensions.FileProviders.NullFileProvider" and WebRootPath is null. However "ContentRootPath" and "ContentRootFileProvider" are non null and accurate. That's about it. Easy enough to Repro – Intensivist Dec 13 '19 at 14:47
  • 1
    OK I finally reproduced the issue. The API template you use doesn't create a `wwwroot` folder, which is why you get a `NullFileProvider`. If you add a `wwwroot` folder (it can be empty), you'll have a `PhysicalFileProvider`. – Métoule Dec 13 '19 at 16:11
  • The above does not work for standalone class libraries where the runtime does not inject into its constructor. Also the default Service provider does not contain an instance of IWebHostEnvironment to just pull it from the container like IWebHostEnvironment hostingEnvironment = ServiceProviderAccessor.GetService(); It is null. so what is the correct pattern to use for a 3rd party library? – john blair May 03 '23 at 09:32
0

In case that somebody is searching for a way to use IWebHostEnvironment outside of the AspNetCore environment (NetStandard2.1 class library for example), Just configure your service class to be generic:

ServiceClass<THostEnvironment>(THostEnvironment hostEnvironment);

And call it from within the AspNetCore like:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<ServiceClass<IWebHostEnvironment>>();
        //... other service connections
    }

Or configure it to consume DependencyInjection in constructor:

How should I inject a DbContext instance into an IHostedService?

Ivan Silkin
  • 381
  • 1
  • 7
  • 15