Use ConfigurationManager with custom path to config file - c#

I see many solutions to reading in values from an external configuration file in a C# console application, but I can't find a solution for my particular circumstances:
Due to reasons of deployment (mainly that this is for a console application that is packed for deployment as part of an MVC website using the Visual Studio web Publish method), the exe does not get packaged with its app.config file.
I'm dependent on libraries that make use of the ConfigurationManager.AppConfig["blah"] syntax, and I can't very well pass in my own AppSettingsSection to these libs.
My console application's .exe file is in the MVC app's bin directory. As both the website and the console app use the same config values, I was trying to simply load the site's Web.config file into the console app, but I haven't found a way of doing this.

The default configuration file is loaded once the AppDomain is loaded. For console applications, the configuration file must be located in the same place as the executable.
I believe that one possible solution is loading an AppDomain as a child of the console application and setting up the AppDomainSetup.ConfigurationFile property rightly to load the configuration file from the custom location, and then execute the whole console application's logic inside the child AppDomain.
You can use this AppDomain.CreateDomain overload for this case (the MSDN article contains a sample code on how to provide the AppDomainSetup):
http://msdn.microsoft.com/en-us/library/aehss7y0.aspx
As far as I know, you can't change the default behavior of where the executable AppDomain looks for the configuration file once it's loaded, but as I suggested you, you can create your own AppDomain with your own requirements!

Related

How to allow for editable .Net generated config files with MSIX?

I am trying to help port a .Net service to a more modern .Net version (possibly Core) and use the MSIX installer. The application has several configuration files generated by the compiler (in source they are app.config but compiled they become *.exe.xml), they are installed into Program File right next to the binaries and a GUI helper app as well and the application itself can modify them to change service behavior (port, ip, tls cert, etc).
Writes under C:\Program Files\WindowsApps\package_name are not allowed.Writes under C:\Program Files\WindowsApps\package_name are not allowed.
The problem I am facing is that the MSIX installer makes it so that files in it's sandboxed version of Program Files cannot be written to (see above). That means that this application cannot be configured, so I am trying to figure out not only how to make the app configurable again, but also how windows wants to handle app configuration.
Right now it seems like there is two general approaches to do this:
write the configuration data to the service account's AppData/local folder
try to mimic a /etc/Myservice behavior in another folder. (meaning a local system-wide directory that houses configuration data for the service)
If you suggest #1 please answer the following additional questions:
How would I move Application configuration files to a user configuration file directory
how can an admin with a normal account modify the config file in the Service Account's AppData folder with the mentioned GUI helper application? (do they need to enable desktop access to the service account, login and run the GUI)?
If you suggest #2:
Where would you suggest this directory exist (specifically where will MSIX allow it)?
How do I tell the .Net application that the files are not right next to it? Can I just use AppData.CurrentDomain.SetData?
Well, a service running on the system account is the same for all users, so I would say that CommonApplicationData is a better folder for storing its settings, instead of appdata. This folder is easily accessible to both your service and to any admin that needs to deploy a custom config file.
In AppData you should store only actual user files (like files or settings generated by the actions taken inside your app by a specific user - thus different files for different users).
Now, the second part is where you need to configure you code to load the config file from a custom path instead of looking for it next to the EXE. I am no .NET expert but after a quick search I found this:
Relocating app.config file to a custom path
The modern approach to deploying app customizations
What is not clear to me is how your customers use the GUI helper tool to customize the config file. Is this just a tool that is used by someone from the IT department to generate the config file, and then they would copy that file and deploy it to the end-user machines using an MSI/MST file (or through some other custom deployment method)?
If your application is only deployed by IT folks, then you can try another simpler (and much elegant) solution for providing it with a custom config file, which actually doesn't require any code changes.
You can still leave the config file next to the EXE, in ProgramFiles and instruct the IT teams that deploy the app to use an MSIX Modification Package to deploy the custom config file generated by your GUI helper. (check the link included above for an example - with a video version at the end of the article).
Note: IT teams can use multiple free or paid tools to generate MSIX Modifications Packages.
Of course, your GUI helper tool still needs to generate that customized config file in a folder where it is allowed, as it can no longer write under ProgramFiles. So actually, you do need to modify a little bit your code in this scenario too.

C# DLL config file not present

Well, this question is a bit different from others with the slightly same title.
I add a config file to my DLL which will be used from a website and a console application.
I'm testing the DLL from my web application.
When I build the DLL I can see my MyApp.dll.config in the bin\debug folder.
Nevertheless, when I try to read the settings from the DLL this way:
var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
The file is not found.
I know it is something to do with the location where the application is being executed as Assembly.GetExecutingAssembly().Location return a path in Framework\v4.0.30319\Temporary ASP.NET Files\root\... while AppDomain.CurrentDomain.BaseDirectory return another completely different path.
So, what I'm doing wrong? There is some configuration missing to get the config file to be copied in the real location where the application is being ran?
Thank you in advance from your help!
Usually when you build a .dll and it has a config, that file lives with the dll in the same folder.
Alas, when you use your dll in another project, that project usually has it's own config, which takes precedence over the dll's one.
You could either add the dll's config to the parent's config, or try configuring what you need in code, instead of in the config.
In .NET DLLs can not have configuration files. They will simply not be used. They are created if you use the settings tab in the project properties, but they will not be read. What you need to do is merge the settings from that config file into the application's configuration (in your case, the web.config file).

Using one app.config file for multiple projects

I have a solution with the following setup:
X amount of class library projects
Y amount of console application projects
Each of these projects may have 0 or more configuration parameters.
Now, I'd like to have only one App.config for user to specify settings and that App.config will only contain parameters of all the reference projects of the console application project to be run.
I've tried giving each project a Settings file and then linking them to the console applications according to their dependencies but that didn't work.
I've also tried just lumping all the configurations together in one class library project and have each console application link to that app.config (or settings file). But that also didn't work (i.e. changes of the app.config or the settings file in the class library will not update the .config of the executable)
Is what I am trying to do possible?
Yes, it is possible. You just need to open the app file. Follow the next example:
ConfigurationManager.OpenExeConfiguration("C:\Test\SomeProject.dll");
XmlNode loggingConfigNode = ConfigurationManager.GetSection("log4net") as XmlNode;
I guess that you will have to open each setting file in order to use the settings, or you will have to consolidate all the settings in a single app.config and then your applications can access the file by open it.

Common app.config for multiple applications

I have several C# console applications, which need to have the same set of settings. I want to avoid duplicity and avoid separate app.config for each application.
Is there any way to read a common app.config file (say common.config) for applications (app1.exe, app2.exe).
Create one file called app.config. Put it in some place outside of your projects' directories, like up in the solution directory. Add it to your projects as a linked item with a relative path to the file. Set the right build action for this item (application configuration) in each project.
Now when each project builds, the file will be copied to the project's output dir with the right name.
You can load an external app.config using the code below:
config = ConfigurationManager.OpenExeConfiguration(Path.Combine("C:\test\root", "Master.exe"));
string logpath = config.AppSettings.Settings["Log.Path"].Value;
And save settings as so:
config = ConfigurationManager.OpenExeConfiguration(Path.Combine("C:\test\root", "Master.exe"));
config.AppSettings.Settings["Log.Path"].Value = "C:\newpath";
config.Save();
You might have to have a master config within one of the applications and point the rest to this. Typically this method is considered bad practice though. There might be issues with different applications locking the file.
#Ran's answer is an option, but each application will still have its own config file after you build. At compile time they will be the same, but at deploy time they are copies.
You can also open one application's config file from another application using:
ConfigurationManager.OpenExeConfiguration(string)
You can have an external config file that all applications reference using:
ConfigurationManager.OpenMappedExeConfiguration
And there's the option to using the Machine config file using:
ConfigurationManager.OpenMachineConfiguration()

Can a Console Application reference its .exe.config if the .config is in another folder?

Here is the task I have been given at work. We have a Web Application for which I created a Console Application that can be executed by the Scheduled Tasks on a daily basis. The task I have be presented with is to discover if we can place the ConApp.exe and the ConApp.exe.config in two different directories (folders) in our application. We would like to place the .exe file in the bin folder with all the .dll's and place the .exe.config file in a central configurations folder. I have been looking around in the properties and such with in Visual Studio and I do not see any options that will allow me to specify to the ConApp.exe the location of the ConApp.exe.config.
Is there a way to place these two files in separate folders or do they need to be in the same folder and have the .exe.confing reference a central .config file?
Thanks, :)
You should be able to use ConfigurationManager.OpenExeConfiguration to do that. You can add a setting in the console application's config file that points out the path and filename to the config file, and pass that value to OpenExeConfiguration (granted that the console runs as an account that has read access to the location where the config file is stored).
Note that if your console app contains statements like ConfigurationManager.AppSettings["somekey"], these will need some rewriting so that they use the Configuration object returned by the OpenExeConfiguration method.
The automatic discovery of the .exe.config works only if the files are in the same folder. But you gave the answer yourself IMHO: have the .exe.config reference another .config file in the desired central location.
No, you cannot tell your app to look in another directory for its main app.config.
What you can do is externalize certain configuration sections to external files in another directory:
<configuration>
<appSettings configSource="config\appSettings.config" />
<connectionStrings configSource="config\connections.config" />
</configuration>
This works - even though in the Visual Studio designer there will be complaints about this - on any .NET configuration section (but not on section groups, e.g. you cannot externalize the entire <system.web> or <system.serviceModel> at once - you need to do it by their sub-elements.
So with help from Fredrik Mork I was able to figure out this solution. First of all when you create your Console Applications, DO NOT, create any setting in the projects properties window. This will create an app.config file in your project which I believe the executable will try to look for and crash if it doesn't find it. When you first create the Console Application and then Build it before writing any code. Visual Studio create the Debug folder with just the executable file and a few supporting files. I then placed this code in the "main" function:
Dim fileMap As ExeConfigurationFileMap = New ExeConfigurationFileMap()
fileMap.ExeConfigFilename = "....../AppName.config"
Dim externalConfig As Configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None)
Dim appS As AppSettingsSection = externalConfig.Sections("appSettings")
Dim reportURL As String = appS.Settings("URL").Value
Console.Writeline(reportURL)
In the 2nd line "fileMap.ExeConfigFilename = "....../AppName.exe.config" then "......" represent the full pathname to the config file and AppName is the name of your file. Now I also tried to copy the code from my original Console Application and run it but it still crashed. I think it is due to the .dlls that I am using which make calls to Stored Procedures on the database. I believe these dlls are looking for the .config file to be in the same folder since that is the way they were built. However, if you are careful when you begin writing your application you can utilize Web.config information like I did above.

Categories