Perhaps this question has been asked before in a different way, but I haven’t been able to find it.
I have one or more plugin adapter assemblies in my application all having the type IPlugin, for instance. Each adapter has its own settings structures stored in a common directory. Whether they are stored in one contiguous file or in separate ones doesn’t matter. Each adapter can have one or more settings associated with it. The settings will have both a name and the Plugin it will be used for.
How would I create such a configuration system using the following requirements:
- I want to use .NETs built in
settings system and avoid writing
one from scratch
- The host application will be
responsible for locating the plugin
settings and passing it to the
plugin
- Each plugin will be
responsible for reading and writing
its own settings to separate
concerns. The host application
should call Plugin.Save(thePath) and
it does its thing.
- All settings are user scoped
So far, I realize that I would need to write my own SettingsProvider, but the provider seems to work in isolation in that there’s no way to pass it parameters such as the path of the plugin directory and the name of the settings. All of the example code I've seen has the provider getting the data from the runtime environment.
The plugins in your example would new up a PluginSettings
and then call into it like this:
PluginSettings["age"] = "5";
int age;
if (int.TryParse(PluginSettings["age"], out age)
{
}
else
{
}
Code for PluginSettings:
using System.Configuration;
using System.Xml;
public sealed class PluginSettings
{
public string this[string propertyName]
{
get
{
var store = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
UserSettingsGroup values = (UserSettingsGroup)store.SectionGroups["userSettings"];
if (values == null)
{
return null;
}
ClientSettingsSection myValues = (ClientSettingsSection)values.Sections[typeof(DebuggerSettings).FullName];
if (myValues == null)
{
return null;
}
SettingElement setting = myValues.Settings.Get(propertyName);
if (setting == null)
{
return null;
}
string returnValue = setting.Value.ValueXml.InnerText;
return returnValue;
}
set
{
var store = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
UserSettingsGroup addSectionGroup = (UserSettingsGroup)store.SectionGroups["userSettings"];
if (addSectionGroup == null)
{
addSectionGroup = new UserSettingsGroup();
store.SectionGroups.Add("userSettings",addSectionGroup);
}
string sectionName = (typeof(DebuggerSettings).FullName);
ClientSettingsSection clientSettingsSection = (ClientSettingsSection)addSectionGroup.Sections[sectionName];
if (clientSettingsSection == null)
{
clientSettingsSection = new ClientSettingsSection();
clientSettingsSection.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
addSectionGroup.Sections.Add(sectionName, clientSettingsSection);
}
SettingElement addMe = new SettingElement(propertyName, SettingsSerializeAs.String);
XmlElement element = new XmlDocument().CreateElement("value");
element.InnerText = value;
addMe.Value.ValueXml = element;
clientSettingsSection.Settings.Add(addMe);
store.Save();
}
}
}
I had the same issue and blogged about it.
I found an answer albeit a bit convoluted and requires going deep into the architecture of .NET, which isn't well documented. Although ApplicationSettingsBase and IApplicationSettingsProvider are decoupled, there is a bit of recoupling involved to make this work. The solution involves modifying the Settings or your own customized version like so:
[SettingsProvider(typeof(CustomSettingProviders.MySettingsProvider))]
internal sealed partial class Settings {
public Settings(string name)
{
this.Context.Add("Name", name);
}
Alternatively, you can get around making changes to this class by setting the Context before it's used like so:
settings.Context.Add("Name", "hello");
In the settings SetPropertyValues of the MySettingsProvider, you can actually grab the data and do something with it:
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
{
if (context.Contains("Name"))
ApplicationName = context["Name"].ToString();
To use the settings, simply instantiate the class with the parametrized constructor, or alternatively set the Context before using it:
var settings = new Properties.Settings("Hello") { Setting1 = "Hello, is anyone home!" }
// alternative: settings.Context.Add("Name", "hello");
settings.Save();