Reputation: 155882
I have a command line app that uses .NET's dependency injection.
It works fine when called in its directory, like C:\GitHub\MyProject\bin\Debug\net9.0>MyApp
However, when I add it to the Path
environment variable and call it from another location it fails:
C:\Users\me>MyApp
Unable to resolve service for type 'MyNamespace.IDependedOnService' while attempting to activate 'MyNamespace.Service'
Both MyNamespace.IDependedOnService
and MyNamespace.Service
are in my code, added in builder.ConfigureServices(...
, but none of that code is in the stack trace.
In fact, the only non Microsoft code in the entire error stack is:
at Program.<Main>$(String[] args) in C:\GitHub\MyProject\Program.cs:line 83
Which is:
using var host = builder.Build();
After much digging it looks like it's picking up config settings in the secrets file, but missing any in C:\GitHub\MyProject\bin\Debug\net9.0\appsettings.config
Why does it only find the settings when run from the same directory?
How should .NET console apps be configured when run from the Path
?
Upvotes: 0
Views: 33
Reputation: 4318
From a .NET point of view it doesn't really matter where your executable file is physically. And it is absolutely correct.
Consider Linux for example. Executables are stored in /usb/sbin but configuration is in your home folder.
You can have one application installed but launched by different users. One binary multiple configurations.
Another example is when you make a single file executable. In this case from my understanding Assembly.Location will become even more irrelevant.
Moreover storing configuration next to binaries can be a vulnerability. In Windows "Program Files" are readable to all users. Ideally your app is not launched under Admin account and therefore can read but can't write there.
So this is why i guess
Upvotes: 0
Reputation: 155882
I think the problem is actually in:
// Init .NET DI host
var builder = Host.CreateDefaultBuilder(args);
As from its documentation:
set the
IHostEnvironment.ContentRootPath
to the result ofDirectory.GetCurrentDirectory()
In this case Directory.GetCurrentDirectory()
returns C:\Users\me
.
The fix is to set the working directory to be the app directory before creating the builder:
Directory.SetCurrentDirectory(AppContext.BaseDirectory);
var builder = Host.CreateDefaultBuilder(args);
...
// Now works
using var host = builder.Build();
This still feels clunky and I'd welcome a better answer/best practice for command line configuration.
Upvotes: 0