Hey! 👋
Great topic—you've basically nailed a dilemma that comes up often when building modular .NET applications.
I’ve faced the same situation and my general rule is: try to keep class libraries as agnostic as possible. Pulling in IWebHostEnvironment directly can definitely be convenient, especially when dealing with file paths (WebRootPath, ContentRootPath) or environment checks—but yeah, it comes at a cost.
What I usually do is define my own abstraction inside the library. Something like:
public interface IAppEnvironment
{
string EnvironmentName { get; }
string ContentRootPath { get; }
// Add only what you actually need
}
Then in the web project, I create an implementation that adapts IWebHostEnvironment to this interface. That way, the library doesn’t know anything about ASP.NET Core, and I can inject a mock easily in unit tests.
Alternatively, if you're only needing one or two pieces of data (like a path or env name), passing them as parameters can often be a better choice. It's simpler and keeps dependencies out of the way.
So in short:
Use interfaces to abstract dependencies
Avoid direct references to ASP.NET Core types in shared libraries
Favor explicit dependencies over pulling the whole context
But yeah—sometimes practicality wins, especially in small internal projects where testability and loose coupling might not be as critical. Still, thinking long-term, I lean toward clean boundaries.
Curious what others are doing too!