Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use / access the app.config from .net code, when called via COM

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
like image 770
MPritchard Avatar asked Feb 18 '10 12:02

MPritchard


3 Answers

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.

like image 104
Gabriel McAdams Avatar answered Sep 30 '22 11:09

Gabriel McAdams


I was facing similar problems with web.config.... I find an interesting solution. You can capsulate configuration reading function, eg. something like this:

public class MyClass {

public static Func<string, string> GetConfigValue = s => ConfigurationManager.AppSettings[s];

//...

}

And then normally use

string connectionString = MyClass.GetConfigValue("myConfigValue");

but in a special case first "override" the function like this:

MyClass.GetConfigValue = s =>  s == "myConfigValue" ? "Hi", "string.Empty";

More about it:

http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/

like image 27
Tuomas Hietanen Avatar answered Sep 30 '22 11:09

Tuomas Hietanen


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.

// CLRLoader.cpp
HRESULT CCLRLoader::CreateLocalAppDomain()
{

    ... snip ...

    // Configure the AppDomain to use a specific configuration file
    pDomainSetup->put_ConfigurationFile(CComBSTR(szConfigFile));

    ... snip ...

}

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.

like image 22
Josh Avatar answered Sep 30 '22 12:09

Josh