I have an existing set of .net libraries that I wish to call from Excel VBA (that part is working fine). These libraries rely on settings in the app.config. I know I can enter these settings in a excel.exe.config file (placed in the same directory as the excel.exe), but this doesn't really seem like a very manageable solution to me, as I can see causing conflicts if more than one application wants to do this.
My question is simple: is there any way of COM exposed dlls referring to their respective config files?
Sample app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="test" value="Hello world!" />
</appSettings>
</configuration>
Sample c#:
namespace ExcelVbaFacingCode
{
public class SimpleAppSettingReader
{
public string GetValue(string key)
{
return ConfigurationManager.AppSettings[key];
}
}
}
Sample VBA:
Public Sub Test()
Dim Test As New SimpleAppSettingReader
Dim sampleValue As String
sampleValue = Test.GetValue("test")
MsgBox "Value: '" + sampleValue + "'", vbOKOnly
End Sub
Whenever
ConfigurationManager.AppSettings
is called, it automatically opens the configuration file of the executing assembly. In your case, Excel is the executing application, so you cannot open the config file of the .Net DLL.This was done for a reason. A single DLL can be called from multiple types of application, each of which might have different requirements (and possibly different databases, for example). For this reason, the application specifies the settings, not the referenced assembly.
I think that what you already suggested is the best way to do this. I know it seems like you are copying your config file, and that it means that you have duplicates out there to worry about when code changes, but its the best thing to do.
You can indeed specify the configuration file that will be used by the .NET configuration API's but you have to do it before the AppDomain is created (which is not as easy as it sounds.) This is how ASP.NET works for example. It sets up the AppDomain to use a "web.config" file located in the virtual directory as opposed to requiring an w3p.exe.config or what not.
You can do this too but you need to create a secondary AppDomain. This in itself is a good idea for a lot of reasons that have to do with multiple add-ins and assembly references. But one of the things you can put in the AppDomain's setup is the name/path of the "app.config" file.
To create the new AppDomain you can use a "shim" which is a bit of boilerplate C++ code that configures and starts the AppDomain and the rest of the code from that point on can be managed code.
There's an article on MSDN written by Andrew Whitechapel and called Isolating Office Extensions with the COM Shim Wizard. I won't lie, it's not a trivial concept, but it's also not too bad. There's a wizard that creates the C++ project for you which loads the .NET addin into a new AppDomain. The configuration of the AppDomain must be done before it is loaded so you'll want to put the following in the wizard-created code.
It's also worth noting that if/when you convert to a VSTO project, the VSTO runtime does all this AppDomain configuration for you. Each VSTO addin runs in its own AppDomain with its own private app.config file.
As I understand it, you want the configuration to be global to the machine where the dll is installed. There is a machine.config file for machine global configuration options. I have never used it myself, so I don't have any more detailed information, but it might be worth looking into. http://msdn.microsoft.com/en-us/library/ms229697(VS.71).aspx. A Google search for "machine.config" gives more hits which look informative.
Another way is to put a custom xml file in the installation directory of the dll file. To get the path to the file, use System.Reflection.Assembly.GetExecutingAssembly.Location (or maybe CodeBase instead of Location). Unfortunately you will have to build your own config management on top of the xml file, but thanks to Linq to XML I think that XML is more painless than ever.
Try:
There is another way to load .config files from COM components that I have been using for several years.
It works like this:
Put a file named "Application.manifest" in the folder. The file must contain:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" />
Put your config file in the same folder. The name of the config file must be "Application.config", i.e. not "myapp.config"
You can use all normal tags in application.config (e.g. runtime, system.diagnostics etc)
I use a vbscript to create the COM+ application:
I was facing similar problems with web.config.... I find an interesting solution. You can capsulate configuration reading function, eg. something like this:
And then normally use
but in a special case first "override" the function like this:
More about it:
http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/