views:

2650

answers:

6

Hi all,

I finally managed to build a working solution of a plugin architecture with help of some guys over here, but now a new problem arises.

My hosting application uses it's app.config file for some defaults for the executing assembly (which is a Windows Service).

Each plugin should be able to load it's own settings from a separate plugin settings file because the host shouldn't be made aware of the plugin settings. In the plugin project I added an app.config file as well (with some settings and a connection string) so that I can instantiate the Properties.Settings class and use it's properties in the plugin code.

The problem is when I change the settings in the app.config of the plugin (which is build as plugin.dll.config) I can't see those changes in the plugin itself, which still uses the design time settings.

Is there a way to load the app.config settings in each plugin so the generated Properties.Settings class will work? If not is there another way to load a app.config based settings file into the plugin? I'm planning on adding a LoadConfiguration method in the IPlugin interface so each plugin will load it's own settings.

Thanks in advance for your help.

+2  A: 

Would something like ConfigurationManager.OpenMappedExeConfiguration help here? You can create a Configuration object reading in the values from a specific file.

Colin Desmond
I actually tried that but somehow this doesn't seem to work.
Erik Beijer
Another problem that keeps this from working is that you'll have a Configuration instance but still the generated Properties.Settings class won't work.
Erik Beijer
+2  A: 

You're working against the architecture of app.config. You get one app.config file per executable (EXE, not DLL). The executable launches, creates its AppDomain, and then loads MyApp.exe.config. You can add app.config objects all you want in Visual Studio, but they are ignored for DLLs. I think what you want to do is manually copy the XML from the dll.config and paste it into the application level app.config. (I'm sure there's a way to automate this using TeamBuild or some such.) The overridden values will then be available to your Properties.Settings class.

Mike Post
Yes but the question clearly states that application shouldn't be aware of the plugin settings.
ChrisF
True, however I would be satisfied if I can somehow dynamically inject the settings from the plugin into the main app.config settings file on runtime. Problem here is I also need the connectionstring setting chapter of the app.config files from my plugins since they nearly all work in SQL Server databases.
Erik Beijer
If each plug-in was created in its own AppDomain (generally a good idea it would appear from other posts on SO), then you might be able to convince it to load a different config file for the new AppContext.
Colin Desmond
Yes I know but since my plugins should be able to communicate with each other (by means of using events between provider and consumer plugins) things should be serialized and such to be able to communicate across AppDomain boundaries.
Erik Beijer
+1  A: 

I prefer to build and use an IConfigManager type plugin. It job is to abstract how the configuration is stored. You receive an instance of it through dependency injection. This way, the IConfigManager implementation can load settings from multiple .config files, from the network, a db or any other source. I also use it to provide default values based on user, machine and/or application - which can be overridden by the user e.g. background colour, font etc.

Other advantages to this method are that settings can be persisted in a consistent way across all plugins - without the plugins having to care, the place where your plugin stores its settings can change transparently (from .config to other) and lastly, the IConfigManager can be mocked during unit testing to simulate different situations.

I hope that helps.

Lee Oades
I am intrigued by this approach. Could you post an example or a link to an example?
Loki Stormbringer
Hi Rick,I'm not sure I could squeeze much of an example into this comment. I don't have a link to anything specific to this answer - I could write a blog post if I had a blog.Was there any part of what I said that you'd like to know more about? I'll see if I can set up a blog somewhere and write about this but it won't be quick.Cheers.
Lee Oades
+1  A: 

Hi, I'm a colleague of Erik. Since he'll be on a well deserved holiday the next few weeks I'll elaborate a bit more on this issue.

In our plugins, we use multiple instances of WCF service clients. The neat thing of these services is that they come with app.config sections which you can use to configure the behavior, servicetype, security, etc. etc.

Now when we load our plugins, these sections are missing from config and therefore the correct endpoints can't be found. Of course we could set them in code, but that kind of whacks the ability to set other config options along the way when needed. We might want to implement ws-security for instance.

So we need a way to load these configs so the plugins can read there respective settings. We could of course merge all configs into one, but that kind of eliminates the "just plugin" method since you would have to manage configs alongside the plugin installation.

I thought about creating a little tool which would merge the 'master' config with all configs placed in a subdir of the project and replace the .exe.config file with that one. I think that would work, but I was wondering if .NET doesn't provide better options. Multiple AppDomains isn't a thing which would work because the plugins have to interact (provider/consumer model) with each other and we don't want to switch to remoting just because of this issue.

Update: I fixed most issues by using the ConfigurationManager to open existing configs for reading appSettings. As for the WCF clients; you can load endpoint/binding configuration for server and client as found here: http://weblogs.asp.net/cibrax/archive/2007/10/19/loading-the-wcf-configuration-from-different-files-on-the-client-side.aspx

Jasper
Are you aware that it's possible to reference an external .config file from the main app.config/web.config? That way, you could keep your plugin settings in a separate file and just add a reference to the main config. You have to register the plugins anyway somehow, so I don't see this as being a big deal.
Aaronaught
A: 

You could make the each plug in read it's own ConfigurationSection then in the main config file use the ConfigSource setting to point to an external file. (See this link for more information)

You don't fully escape having plugin config information in the main app.config file but at least the plugin specific settings are in separate files.

Loki Stormbringer
A: 

I usually prefer to avoid the whole app.config mess by creating a dedicated Xml file that the host processes with the plugin's settings also inside. The Xml would look something like this:

<root>
    <Settings>
        Here's where anything specific to the app goes.
    </Settings>
    <plugins>
        <plugin type="mylibrary.myclass">
            Here I let the plugin serialize itself however it wants to.
        </plugin>
    </plugins>
</root>

The hosting app then creates the plugin from the type attribute and tests if the class implements ISerializable; if it does, then the plugin will deserialize itself. It's a bit scary to have the plugins inline with the app's settings, but if you load the plugin's substring of Xml into a new XmlReader then you don't have to worry about an error in the plugin from reading too far in the Xml string.

Alexander Eisenhart