Accessing App.config in a location different from the binary - c#

In a .NET Win console application, I would like to access an App.config file in a location different from the console application binary. For example, how can C:\bin\Text.exe get its settings from C:\Test.exe.config?

using System.Configuration;
Configuration config =
ConfigurationManager.OpenExeConfiguration("C:\Test.exe");
You can then access the app settings, connection strings, etc from the config instance. This assumes of course that the config file is properly formatted and your app has read access to the directory. Notice the path is not "C:\Test.exe.config" The method looks for a config file associated with the file you specify. If you specify "C:\Test.exe.config" it will look for "C:\Test.exe.config.config" Kinda lame, but understandable, I guess.
Reference here: http://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.openexeconfiguration.aspx

It appears that you can use the AppDomain.SetData method to achieve this. The documentation states:
You cannot insert or modify system entries with this method.
Regardless, doing so does appear to work. The documentation for the AppDomain.GetData method lists the system entries available, of interest is the "APP_CONFIG_FILE" entry.
If we set the "APP_CONFIG_FILE" before any application settings are used, we can modify where the app.config is loaded from. For example:
public class Program
{
public static void Main()
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", #"C:\Temp\test.config");
//...
}
}
I found this solution documented in this blog and a more complete answer (to a related question) can be found here.

Use the following (remember to include System.Configuration assembly)
ConfigurationManager.OpenExeConfiguration(exePath)

You can set it by creating a new app domain:
AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ConfigurationFile = fileLocation;
AppDomain add = AppDomain.CreateDomain("myNewAppDomain", securityInfo, domainSetup);

AppDomainSetup domainSetup = new AppDomainSetup();
domainSetup.ConfigurationFile = #"D:\Mine\Company\";
string browserName = ConfigurationManager.AppSettings["browser"];

Related

Specflow - Create Pre-defined data to be shared between all scenarios in test execution with parallel execution

I am trying to Re-create my BeforeTestRun step to run my setup only once per whole execution not per thread.
I had a look a Custom Deployment steps I have implemented some already but For my setup i need to bring in some values from the app.config file I am trying something like this
my Default.srprofile file contains:
<DeploymentTransformation>
<GlobalSteps>
<Custom type="Test.CustomDeploymentStep, Test"></Custom>
</GlobalSteps>
</DeploymentTransformation>
and my CustomDeploymentStep.cs:
public class CustomDeploymentStep : IDeploymentTransformationStep
{
public static string baseUrl;
public void Apply(IDeploymentContext deploymentContext)
{
baseUrl = ConfigurationManager.AppSettings["URL"];
}
public void Restore(IDeploymentContext deploymentContext)
{
DoSomething();
}
}
My app config contains the following:
<add key="URL" value="http://google.com" />
But That does not work, The ConfigurationManager.AppSettings only returns one key and one value
"key" : "TestProjectRetargetTo35Allowed" "value":"true"
How can I load my configuration from app.config into the Apply() method in CustomDeploymentStep?
Also If there is a better/more efficient way of generating pre-defined data in specflow with thread safe execution, please do let me know
I ran into the same problem once I needed to use custom deployment steps in more than one project in a large solution. This appears to be a bug within the TechTalk.SpecRun.Framework. The error is likely "Error applying global deployment step. Global steps cannot contain test assembly specific settings." and if you look inside the TestAssembly while debugging you will see the TestAssemblyConfigFilePath is null and/or swallowing another exception.
It doesn't register a project specific configuration file. My workaround was to save the config file into debug and access what I need like so:
string appConfigFilePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\App.config";
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap();
configMap.ExeConfigFilename = appConfigFilePath;
var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);
var baseUrl = config.AppSettings.Settings["URL"].Value;

Load a WPF app.config / MyApp.exe.config from a location different from the app binary directory

I would like to load the MyApp.exe.config from a sub folder of the app bin folder rather than the app bin folder itself (eg ./Configs/MyApp.exe.config).
I dont want to have to work with a System.Configuration object (as returned by ConfigurationManager.OpenExeConfiguration(configPath) because this is just a string map. I would like to keep working with the existing generated Settings : ApplicationSettingsBase object in Settings.Designer.cs as that has setting values cast to proper objects.
I.e I just want to redirect where Settings loads itself from. Ive had a look round and all I can find are solutions that involve working directly with System.Configuration object directly - but how to rewire this up to Settings?
Kind of seems a reasonable thing to want to do - can't understand why it appears so difficult? Any solutions most welcome!
Jims solution is clean when you have a single configSection in the app.config. In our case we have several configSections (for app, libraries, nlog etc) and we want to just load the whole file from a new location. This wasnt really clear from the orignal question.
The eaisest way to do this seemed to be to use a new AppDomain with an AppDomainSetup object on which we set the ConfigurationFile property to path to new config file.
The question is then when and how to create the new app domain. This post offers an elegant solution that seems to work with minor modifications.
1: Add a Startup event handler:
Application x:Class="InstallTool.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="AppStartup"
2: In that handler (in the default application domain) create a new application domain - the creation of which just recursively calls the Startup event handler. When the new app domain is finsihed with (app closed) just closed it an abort startup in the "outer" app domain. This avoids having to make cross app domain calls or have a bootstrapper app to create the new app domain.
public void AppStartup(object sender, StartupEventArgs e) {
if (AppDomain.CurrentDomain.IsDefaultAppDomain()) {
string appName = AppDomain.CurrentDomain.FriendlyName;
var currentAssembly = Assembly.GetExecutingAssembly();
// Setup path to application config file in ./Config dir:
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = System.Environment.CurrentDirectory;
setup.ConfigurationFile = setup.ApplicationBase +
string.Format("\\Config\\{0}.config", appName);
// Create a new app domain using setup with new config file path:
AppDomain newDomain = AppDomain.CreateDomain("NewAppDomain", null, setup);
int ret = newDomain.ExecuteAssemblyByName(currentAssembly.FullName, e.Args);
// Above causes recusive call to this method.
//--------------------------------------------------------------------------//
AppDomain.Unload(newDomain);
Environment.ExitCode = ret;
// We get here when the new app domain we created is shutdown. Shutdown the
// original default app domain (to avoid running app again there):
// We could use Shutdown(0) but we have to remove the main window uri from xaml
// and then set it for new app domain (above execute command) using:
// StartupUri = new Uri("Window1.xaml", UriKind.Relative);
Environment.Exit(0);
return;
}
}
What you need is a custom SettingsProvider. The default for your local application is LocalFileSettingsProvider, which gets the settings from the appname.exe.config file in the same directory as appname.exe. You might be able to create a class derived from LocalFileSettingsProvider, which looks in a different directory. Failing that, you'll have to derive from SettingsProvider.
Also see ApplicationSettingsBase.Providers property.
Ricibob's solution works fine, if you don't have Threads/Background tasks in your application. If you do have them it causes problems. Moreover you can achieve the above solution in one line:
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", YOUR_CONFIG_LOCATION);

C# Class Library: StreamWriter writing to system32 folder

I have a class library which is deployed on an ISP server to be consumed by an ASP.NET web service. I'd like to keep track of any errors and in this case the windows event log is inaccessible to me. So I thought I'd write to a txt file using the StreamWriter class. Problem is if I don't give an absolute path and just a file name it tries to write to C:\Windows\System32, and that's no good to me.
How can I tell it to use maybe the data directory or the application root? Any thoughts?
Use Server.MapPath to get a path relative to the web application.
using (FileStream fs = new FileStream(Server.MapPath("~/logs/logfile.txt"),
FileMode.Append)) {
//do logging here.
}
While some of the previous posters have suggested using reflection to get the executing assembly, I'm not sure whether or not that will net you the web application or the w3wp process. If it's the latter, you're still going to end up trying to write to the System32 folder.
Here is what I used to use, it's a little clunky but it gets the job done:
using System;
using System.Collections.Generic;
using System.Web.UI;
public static class Logger
{
private static readonly Page Pge = new Page();
private static readonly string Path = Pge.Server.MapPath("~/yourLogPath/Log.txt");
private const string LineBreaker = "\r\n\r======================================================================================= \r\n\r";
public static void LogError(string myMessage, Exception e)
{
const LogSeverity severity = LogSeverity.Error;
string messageToWrite = string.Format("{0} {1}: {2} \r\n\r {3}\r\n\r {4}{5}", DateTime.Now, severity, myMessage, e.Message, e.StackTrace, LineBreaker);
System.IO.File.AppendAllText(Path, messageToWrite);
}
}
I had this class in it's own project, separate from the website itself, and I used it in all of my other non website projects...
Edit:
Btw LogSeverity is just an enum I made up...
In my web product, in the web.config I specify an appSettings block like this:
<configuration>
<appSettings>
<add key="MyLogPath" value="LogPath" />
</appSettings>
</configuration>
which you can use from the code like
ConfigurationManager.AppSettings["MyLogPath"]
then you can have the installer configure it to wherever you want. you probably don't want the log files in your application directory.
Try checking out:
Application.StartupPath;
Here's a link to the docs
Gets the path for the executable file
that started the application, not
including the executable name.
string path = Application.StartupPath;
Note: you'll still need to add a file name.
You can find out the path of your executable by doing this:
string path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

How to access app configuration from a .dll?

I recently broke out a part of my winform app in a .dll. Some of the classes in that dll
wants fetch/store user settings.
The classes just used the VS generated Settings file so it just did
Properties.Settings.Default.SomeSetting = var;Properties.Settings.Default.Save() etc.
What are my options now that I moved that code out to a class library/.dll ?
The hosting application should handle the interface to the config file, not the DLL. Either
Pass whatever settings need to be read/modified within the DLL as parameters, or
Pass in a name-value collection of settings that can be modified by the DLL, and save whatever changes are made by the DLL to the collection when control returns to the calling application.
This is similar in principle to removing a database interface from the business layer of a tiered application and encapsulating it into a data layer.
It doesn't make a lot of sense to me to have a DLL storing user settings. A DLL is a library, not an application, and doesn't directly interact with the user. If classes in the DLL need access to user settings, you can pass them in as parameters.
The Properties class is autogenerated. It is really a wrapper on the config file. If you don't want to change your design, just go into the code and copy it to your DLL. But remember it will no longer be magically maintained (regenerated). Or you can use ConfigurationManager to get at config file directly.
I would not recommand it (better use your own class for settings), but you can try this:
string sectionName = "applicationSettings/" +
appName + ".Properties.Settings";
System.Configuration.ClientSettingsSection section =
(System.Configuration.ClientSettingsSection)
System.Configuration.ConfigurationManager.GetSection(sectionName);
foreach (SettingElement setting in section.Settings)
{
string value = setting.Value.ValueXml.InnerText;
string name = setting.Name;
if (name.ToLower().StartsWith(searchName.ToLower()))
{
return value;
}
}
For those who need to read settings from userDirectory/user.config, here is a solution:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
ConfigurationSectionGroup userSettings = config.GetSectionGroup("userSettings");
ClientSettingsSection settings = (ClientSettingsSection)userSettings.Sections.Get("[applicationName].Properties.Settings");
SettingElement elem = settings.Settings.Get([settingName]);
var sett = elem.Value.ValueXml.InnerText;

Get executing assembly name from referenced DLL in C#

What is the best way to get the application name (i.e MyApplication.exe) of the executing assembly from a referenced class library in C#?
I need to open the application's app.config to retrieve some appSettings variables for the referenced DLL.
To get the answer to the question title:
// Full-name, e.g. MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
string exeAssembly = Assembly.GetEntryAssembly().FullName;
// or just the "assembly name" part (e.g. "MyApplication")
string exeAssemblyName = Assembly.GetEntryAssembly().GetName().Name;
As mentioned by #Ben, since you mention wanting to get the configuration information, use the ConfigurationManager class.
If you want to get the current appdomain's config file, then all you need to do is:
ConfigurationManager.AppSettings....
(this requires a reference to System.Configuration of course).
To answer your question, you can do it as Ray said (or use Assembly.GetExecutingAssembly().FullName) but I think the problem is easier solved using ConfigurationManager.
To get the exact name without versions, etc. use:
string appName = Assembly.GetEntryAssembly().GetName().Name;
Works with .NET v1.1 and later.
You can get the assembly through the class type...
typeof(MyClass).Assembly
If you want the name of the parent EXE and not the referenced DLL assembly - you will need to use this:
Assembly.GetEntryAssembly().GetName().Name
This will return the EXE name (minus the .EXE part).
Using GetExecutingAssembly() is not right as per the OP's question (first paragraph of it!) as it will return the DLL name.
You should never couple your libraries to a consumer (in this case Web, WinForm or WCF app). If your library needs configuration settings, then GIVE it to the library.
Don't code the library to pull that data from a consumer's config file. Provide overloaded constructors for this (that's what they are for).
If you've ever looked at the ConfigurationManager.AppSettings object, it is simply a NameValueCollection. So create a constructor in your library to accept a NameValueCollection and have your consumer GIVE that data to the library.
//Library
public class MyComponent
{
//Constructor
public MyComponent(NameValueCollection settings)
{
//do something with your settings now, like assign to a local collection
}
}
//Consumer
class Program
{
static void Main(string[] args)
{
MyComponent component = new MyComponent(ConfigurationManager.AppSettings);
}
}
If you want to read (and display) version number:
Assembly ass = System.Reflection.Assembly.GetExecutingAssembly();
AssemblyName assname = ass.GetName();
Version ver=assname.Version;
Somewhere in application (ie Title block in a Windows form)
this.Text = "Your title Version " + ver;
For the short name of an assembly from a class instance:
Me.GetType ().Assembly.GetName().Name

Categories