Methods for composing configuration for composite applications (eg PRISM, MEF)
Frameworks such as PRISM and MEF make it very easy to design complex applications out of multiple, composable components. One common example of this is a plug-in architecture where an application shell can be dymanically reconfigured with plug-in UI components (eg by dropping DLLs into a Plug-ins
directory).
This is all well and good, but as Vaccano spotted in Can Prism be modular when calling webservices? there are circumstances where each individual plug-in requires its own set of configuration - WCF bi开发者_开发知识库ndings being a typical example, but there are many other scenarios (logging, database connections, etc.) with similar needs.
So, as I see it, the options we have are:
- All config goes into the
App.config
of the shell application (which as Vaccano mentioned breaks the whole encapsulation & deployment advantages of this model), or - Each plug-in assembly uses a bespoke mechanism for config (eg an embedded resource) and then uses this to dynamically configure a WCF service, for example (which at best is messy and time consuming, and at worst may not be possible)
Neither of these options are ideal, but they are workarounds. However, the ideal situation would be for each plug-in DLL to have either self contained config (such as an embedded resource file) or an Xxx.dll.config
file, and have each of these XML config fragments merged into the App.config
configuration of the shell application dynamically at runtime. This is reminiscent of the way Machine.config
and App.config
files are merged.
My question, therefore, is: has anyone come across any existing frameworks or techniques which could be used to allow this dynamic merging of composite config files into the in-process configuration of the container application? I am surprised not to see this as part of PRISM or MEF and therefore slightly wary of posting this question in case I have missed something obvious - if so, please just quietly post the relevant link :)
We've run up against the same problem. I've not found a solution to this either.
Here's two things I've seen people do (or we've done):
Manual Service Endpoint Registration
Create an application service registry that says how to make a ChannelFactory from a T. Each Module can contribute to this in IModule Initialize by calling RegisterService<T>
and all subordinate views of that Module can get their Channel Factories from it:
public interface IServiceRegistry
{
void RegisterService<T>(ServiceEndpoint ep);
ChannelFactory<T> GetService<T>();
}
Instead of returning ChannelFactory<T>
here you could just return T
of course (caveat emptor). View/ViewModels would simply ask for an IServiceRegistry as a dependency and grab their service proxies this way. This also provides a convenient place for isolation when writing unit tests.
Embedded Config
A system of conventions roughly doing the same thing as above, but based on config embedded in the DLL (as you suggested) and utilizing named configurations. You'd consume this in the same way as above, but it would be a slightly different experience. We use the convention "Endpoints.config" embedded in our DLL and read from that.
public interface IServiceChannelFactoryFactory //I'm terrible at naming
{
//This is much like the generated concrete class when you use "Add Service Reference"
//Except there is no method with an empty parameter
ChannelFactory<T> GetService<T>(string endpointName);
}
Our "Endpoints.config" has multiple endpoints per endpointName with attributes added that make that endpoint unique for the environment (DEV, QA, Staging, Production). I don't know if this is a concern for you, but it was a convenient place to put this kind of config.
Both work. It's surprising to me that I've not seen more people talk about this. Great question.
The Composite Services guidance project from the patterns & practices (the same team that brought you Prism) provides design and implementation patterns for service discovery, composition and integration.
As to dynamic config merging, take a look at the implementation of complex config scenarios we have in Enterprise Library 5.0. It's not a generic one and only focused on Enterprise Library configuration, but you can still examine the source code.
For a Windows/WPF app, you may be able to accomplish this by creating a custom settings provider -- this is a class that you build that plugs into the .net config system.
In theory, You could put your settings into module-specific config files. You would build a settings provider that knows how to look for these module-specific files at runtime, and provides the settings. Since this sits "below" the configuration consumers in the stack, WCF, or another technology should not need know anything special to use it. Only drawback is that it does not appear to be supported in Silverlight.
Here's link to a code project article where one is implemented: http://www.codeproject.com/KB/vb/CustomSettingsProvider.aspx
Here is a link to the MSDN documentation: http://msdn.microsoft.com/en-us/library/system.configuration.settingsprovider.aspx
精彩评论