Im trying to add an app.config file to my DLL, but all attempts have failed.
According to MusicGenesis in 'Putting configuration information in a DLL' this should not be a problem. So obviously I'm doing something wrong...
The following code should return my ConnectionString from my DLL:
return ConfigurationManager.AppSettings["ConnectionString"];
However, when I copy the app.config file to my console application, it works fine.
Any ideas?
It is not trivial to create a .NET configuration file for a .DLL, and for good reason. The .NET configuration mechanism has a lot of features built into it to facilitate easy upgrading/updating of the app, and to protect installed apps from trampling each others configuration files.
There is a big difference between how a DLL is used and how an application is used. You are unlikely to have multiple copies of an application installed on the same machine for the same user. But you may very well have 100 different apps or libraries all making use of some .NET DLL.
Whereas there is rarely a need to track settings separately for different copies of an app within one user profile, it's very unlikely that you would want all of the different usages of a DLL to share configuration with each other. For this reason, when you retrieve a Configuration object using the "normal" method, the object you get back is tied to the configuration of the App Domain you are executing in, rather than the particular assembly.
The App Domain is bound to the root assembly which loaded the assembly which your code is actually in. In most cases this will be the assembly of your main .EXE, which is what loaded up the .DLL. It is possible to spin up other app domains within an application, but you must explicitly provide information on what the root assembly of that app domain is.
Because of all this, the procedure for creating a library-specific config file is not so convenient. It is the same process you would use for creating an arbitrary portable config file not tied to any particular assembly, but for which you want to make use of .NET's XML schema, config section and config element mechanisms, etc. This entails creating an ExeConfigurationFileMap
object, loading in the data to identify where the config file will be stored, and then calling ConfigurationManager
.OpenMappedExeConfiguration
to open it up into a new Configuration
instance. This will cut you off from the version protection offered by the automatic path generation mechanism.
Statistically speaking, you're probably using this library in an in-house setting, and it's unlikely you'll have multiple apps making use of it within any one machine/user. But if not, there is something you should keep in mind. If you use a single global config file for your DLL, regardless of the app that is referencing it, you need to worry about access conflicts. If two apps referencing your library happen to be running at the same time, each with their own Configuration
object open, then when one saves changes, it will cause an exception next time you try to retrieve or save data in the other app.
The safest and simplest way of getting around this is to require that the assembly which is loading your DLL also provide some information about itself, or to detect it by examining the App Domain of the referencing assembly. Use this to create some sort of folder structure for keeping separate user config files for each app referencing your DLL.
If you are certain you want to have global settings for your DLL no matter where it is referenced, you'll need to determine your location for it rather than .NET figuring out an appropriate one automatically. You'll also need to be aggressive about managing access to the file. You'll need to cache as much as possible, keeping the Configuration
instance around ONLY as long as it takes to load or to save, opening immediately before and disposing immediately after. And finally, you'll need a lock mechanism to protect the file while it's being edited by one of the apps that use the library.
if you want to read settings from the DLL's config file but not from the the root applications web.config or app.config use below code to read configuration in the dll.
var appConfig = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
string dllConfigData = appConfig.AppSettings.Settings["dllConfigData"].Value;
I had the same problem and searched the web for several hours but I couldn't find any solution so I made my own. I wondered why the .net configuration system is so inflexible.
Background: I want to have my DAL.dll to have its own config file for database and DAL settings. I also need the app.config for Enterprise Library and its own configurations. So I need both the app.config and dll.config.
What I did not wanted to do is pass-through every property/setting from the app to my DAL layer!
to bend the "AppDomain.CurrentDomain.SetupInformation.ConfigurationFile" is not possible because I need it for the normal app.config behavior.
My requirements/point of views were:
NO manual copy of anything from ClassLibrary1.dll.config to WindowsFormsApplication1.exe.config because this is unreproducible for other developers.
retain the usage of strong typing "Properties.Settings.Default.NameOfValue" (Settings behavior) because I think this is a major feature and I didn't want to lose it
I found out the lack of ApplicationSettingsBase to inject your own/custom config file or management (all necessary fields are private in these classes)
the usage of "configSource" file redirection is not possible because we would have to copy/rewrite the ClassLibrary1.dll.config and provide several XML files for several sections (I also didn't like this)
I didn't like to write my own SettingsProvider for this simple task as MSDN suggests because I thought that simply would be too much
I only need sections applicationSettings and connectionStrings from the config file
I came up with modifying the Settings.cs file and implemented a method that opens the ClassLibrary1.dll.config and reads the section information in a private field. After that, I've overriden "this[string propertyName]" so the generated Settings.Desginer.cs calls into my new Property instead of the base class. There the setting is read out of the List.
Finally there is the following code:
internal sealed partial class Settings
{
private List<ConfigurationElement> list;
/// <summary>
/// Initializes a new instance of the <see cref="Settings"/> class.
/// </summary>
public Settings()
{
this.OpenAndStoreConfiguration();
}
/// <summary>
/// Opens the dll.config file and reads its sections into a private List of ConfigurationElement.
/// </summary>
private void OpenAndStoreConfiguration()
{
string codebase = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;
Uri p = new Uri(codebase);
string localPath = p.LocalPath;
string executingFilename = System.IO.Path.GetFileNameWithoutExtension(localPath);
string sectionGroupName = "applicationSettings";
string sectionName = executingFilename + ".Properties.Settings";
string configName = localPath + ".config";
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = configName;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
// read section of properties
var sectionGroup = config.GetSectionGroup(sectionGroupName);
var settingsSection = (ClientSettingsSection)sectionGroup.Sections[sectionName];
list = settingsSection.Settings.OfType<ConfigurationElement>().ToList();
// read section of Connectionstrings
var sections = config.Sections.OfType<ConfigurationSection>();
var connSection = (from section in sections
where section.GetType() == typeof(ConnectionStringsSection)
select section).FirstOrDefault() as ConnectionStringsSection;
if (connSection != null)
{
list.AddRange(connSection.ConnectionStrings.Cast<ConfigurationElement>());
}
}
/// <summary>
/// Gets or sets the <see cref="System.Object"/> with the specified property name.
/// </summary>
/// <value></value>
public override object this[string propertyName]
{
get
{
var result = (from item in list
where Convert.ToString(item.ElementInformation.Properties["name"].Value) == propertyName
select item).FirstOrDefault();
if (result != null)
{
if (result.ElementInformation.Type == typeof(ConnectionStringSettings))
{
return result.ElementInformation.Properties["connectionString"].Value;
}
else if (result.ElementInformation.Type == typeof(SettingElement))
{
return result.ElementInformation.Properties["value"].Value;
}
}
return null;
}
// ignore
set
{
base[propertyName] = value;
}
}
You just will have to copy your ClassLibrary1.dll.config from the ClassLibrary1 output directory to your application's output directory. Perhaps someone will find it useful.
When using ConfigurationManager, I'm pretty sure it is loading the process/AppDomain
configuration file (app.config / web.config). If you want to load a specific config file, you'll have to specifically ask for that file by name...
You could try:
var config = ConfigurationManager.OpenExeConfiguration("foo.dll");
config.ConnectionStrings. [etc]
ConfigurationManager.AppSettings returns the settings defined for the application, not for the specific DLL, you can access them but it's the application settings that will be returned.
If you're using you dll from another application then the ConnectionString shall be in the app.settings of the application.
I know this is late to the party, however I thought I would share the solution I use for DLL's.
I am more of the K.I.S.S. school of thinking, so when I have a .NET DLL that wants to store external data points that control how it works or where it goes, etc. I simply create a "config" class that has only public properties that store all the data points it needs and that I would like to be able to have controlled external to the DLL to prevent recompiling it to make the changes. Then I use .Net's XML Serializing to save and load the object representation of the class to a file.
There are a lot of ways then to handle reading it and accessing it, from a Singleton, a static utility class, to extension methods, etc. This depends on how your DLL is structured and what method will fit your DLL best.
you are correct, you can read the config file of a dll. I struggled with this for a day until i found out that the my config file was the issue. See my code below. it was able to run.
ExeConfigurationFileMap map = new ExeConfigurationFileMap();
map.ExeConfigFilename = Assembly.GetExecutingAssembly().Location + ".config";
Configuration libConfig = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
AppSettingsSection section = (libConfig.GetSection("appSettings") as AppSettingsSection);
Console.WriteLine(section.Settings["dnd_shortcodes"].Value);
my Plugin1.dll.config
looked as below;
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="cmd_location" value="http://..."/>
<add key="dnd_shortcodes" value="142,145,146,157,165,167,168,171,173,176,178,404,40"/>
</appSettings>
</configuration>
I found out that my config file lacked the <appSettings>
tag, so look around, your issue could have been different but not so far from mine.
The full solution is not often found in one place ... 1) Create an app config file and name it "yourDllName.dll.config" 2) Right click on the config file created above in VS Solution Explorer, click properties --- set "Build Action" = Content --- set "Copy To Output Directory" = Always 3) Add an appSettings section to the configuration file (yourDllName.dll.config) with your yourKeyName and yourKeyValue
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="yourKeyName" value="yourKeyValue"/>
</appSettings>
</configuration>
4) Add System.Configuration to your dll/class/project references 5) Add the using statements to your code where you intend to access the config setting
using System.Configuration;
using System.Reflection;
6) To access the value
string keyValue = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location).AppSettings.Settings["yourKeyName"].Value;
7) rejoice, it works
IMHO, this should only be used when developing a new dll/library.
#if (DEBUG && !FINALTESTING)
string keyValue = ConfigurationManager.OpenExeConfiguration...(see 6 above)
#else
string keyValue = ConfigurationManager.AppSettings["yourKeyName"];
#endif
The config file ends up being a great reference, for when you add the dll's appSettings to your actual application.
Since the assembly resides in a temporary cache, you should combine the path to get the dll's config:
var appConfig = ConfigurationManager.OpenExeConfiguration(
Path.Combine(Environment.CurrentDirectory, Assembly.GetExecutingAssembly().ManifestModule.Name));
If you're using libraries that look up a large amount of configation behind-the-scenes, such as WCF, you might consider doing this:
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config");
Or in PowerShell:
[AppDomain]::CurrentDomain.SetData("APP_CONFIG_FILE", "MyWcfClientWrapper.dll.config")
IMO this technique is a code smell and is really only suitable for use in ad hoc scripting. If you find yourself wanting to do this in production code, maybe it's time for an architectural review.
The following is NOT recommended: As a technical curiosity, here's a variation on the theme. You can create a static constructor inside one of the classes housed in the DLL, and make this call from there. I wouldn't recommend doing this except as a last resort.
Seems like this config files are really confusing to clarify as their behaviour changes from the dev environment to deployment. Apparently a DLL can have its own config file, but once you copy and paste the dll (together with their config file) elsewhere, the whole thing stopped working. The only solution is to manually merge the app.config files into a single file, which will only be used by the exec. For e.g. myapp.exe will have a myapp.exe.config file that contains all settings for all dlls used by myapp.exe. I'm using VS 2008.
I've found what seems like a good solution to this issue. I am using VS 2008 C#. My solution involves the use of distinct namespaces between multiple configuration files. I've posted the solution on my blog: http://tommiecarter.blogspot.com/2011/02/how-to-access-multiple-config-files-in.html.
For example:
This namespace read/writes dll settings:
var x = company.dlllibrary.Properties.Settings.Default.SettingName;
company.dlllibrary.Properties.Settings.Default.SettingName = value;
This namespace read/writes the exe settings:
company.exeservice.Properties.Settings.Default.SettingName = value;
var x = company.exeservice.Properties.Settings.Default.SettingName;
There are some caveats mentioned in the article. HTH
As Marc says, this is not possible (although Visual Studio allows you to add an application configuration file in a class library project).
You might want to check out the AssemblySettings class which seems to make assembly config files possible.
It confusing to mock a "real" application configuration file. I suggest you roll your own because it is quite easy to parse an XML file using e.g. LINQ.
For example create an XML file MyDll.config like below and copy it alongside the DLL. To Keep it up to date set its property in Visual Studio to "Copy to Output Directory"
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<setting key="KeyboardEmulation" value="Off"></setting>
</configuration>
In your Code read it like this:
XDocument config = XDocument.Load("MyDll.config");
var settings = config.Descendants("setting").Select(s => new { Key = s.Attribute("key").Value, Value = s.Attribute("value").Value });
bool keyboardEmulation = settings.First(s => s.Key == "KeyboardEmulation").Value == "On";
In this post a similar problem was discussed and solve my problem How to load a separate Application Settings file dynamically and merge with current settings? might be helpfu
For a dll, it should not depend on configuration as configuration is owned by application and not by dll.
This is explained at here
you can use this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace GClass1
{
[Guid("D6F88E95-8A27-4ae6-B6DE-0542A0FC7039")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _GesGasConnect
{
[DispId(1)]
int SetClass1Ver(string version);
}
[Guid("13FE32AD-4BF8-495f-AB4D-6C61BD463EA4")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("InterfacesSMS.Setting")]
public class Class1 : _Class1
{
public Class1() { }
public int SetClass1(string version)
{
return (DateTime.Today.Day);
}
}
}
Success story sharing