Upgrade to .NET Core 3.1 - Can't instantiate singleton PhysicalFileProvider in services

643 views Asked by At

I have a .NET Core solution containing an API project that was targeting .NET Core 2.1, and I upgraded it to .NET Core 3.1. I've realized that there is a number of breaking changes from doing that, which I have gone through and modified to be compatible (such as converting UseMvc to UseRouting and so). But now I am stuck on one:

When I try to run the API project, I get this runtime error:

Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Microsoft.Extensions.FileProviders.IFileProvider Lifetime: Singleton ImplementationType: Microsoft.Extensions.FileProviders.PhysicalFileProvider': No constructor for type 'Microsoft.Extensions.FileProviders.PhysicalFileProvider' can be instantiated using services from the service container and default values.)

In Startup.cs, ConfigureServices, there is:

services.AddSingleton<IFileProvider, PhysicalFileProvider>();

which of course is the issue. But I'm not sure how do I convert this to be both compatible and have the API work the way it has been.

I did find an article on file providers that states:

The FileProviderSample sample app creates the provider in the Startup.ConfigureServices method using IHostEnvironment.ContentRootFileProvider:

var physicalProvider = _env.ContentRootFileProvider;

But it's not clear as to exactly where within ConfigureServices that is supposed to go... or if that replaces the AddSingleton... or how that's going to affect the API's behavior. So I'm not sure what to do with this.

1

There are 1 answers

0
Rodrigo Rodrigues On

How would DI create an instance of PhysicalFileProvider without specifying a root directory?

You could create an instance by yourself specifying the root, then registering that instance into the services collection.

This works for me:

public void ConfigureServices(IServiceCollection services) {
  // (...)
  IFileProvider fp = new PhysicalFileProvider("C:\\path\\to\\by\\root");
  // or, you could get the file provider from the environment:
  // IFileProvider fp = _env.ContentRootFileProvider;
  services.AddSingleton<IFileProvider, PhysicalFileProvider>(_ => fp);
  // (...)
}

Then, I just inject it into my DI managed class:

IFileProvider _fileProvider;

public FilesController(IFileProvider fp) {
  this._fileProvider = fp;
}

As an alternative, and If you don't mind changing the constructor parameters of your class, you could inject IWebHostEnvironment instead. Then you could have easy access to the file provider from environment.