0

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?

2
  • Without a Minimal Reproducible Example, it's impossible for anyone to answer your question and your question will be unhelpful to others Googling for this particular problem. Commented Mar 6 at 10:27
  • @Steven create a new .NET command line app, throw an error for missing config, add Path and run from another location. Happens for all local config files types (json, xml or ini). Minimal repo is hard because the Path reg key and running it from another location are required. Commented Mar 7 at 17:00

2 Answers 2

0

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 of Directory.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.

Sign up to request clarification or add additional context in comments.

Comments

0

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

3 Comments

Yeah, that's why this seems backwards - the config should default to where the exe is, but anything the user inputs (say file paths) should be relative to where they're running it from. In this case the app connects to a lot of microservices and the config contains all the addresses to reach them (not the credentials, which come from the user's account) - I don't want to hard code them (there's a load and they occasionally change address) but they aren't secure information.
Pentesters report this as a vulnerability if potentially other people has access to machine (even if not). For example config file with a db password next to exe in "Program Files" is readable by all and nothing you can do. The same file in ProgramData or other user folder is ok. We spend a lot of time on this and in the end everything not in built is outside now.
it's not the password or account detail in config, it's all the other settings. Which instance and which version of each microservice, how many days later is that thing due, which folder holds the template files, what name should errors be logged under, that sort of detail. We've been putting it next to the .exe since the days of .ini files, but Path is also ancient and user input is local.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.