Da qualche giorno mi sto divertendo con la gestione dei settings in un'applicazione WinForms (ApplicationSettingsBase, settings providers e compagnia bella).
Ho trovato un po' ostico il salvataggio delle impostazioni che devono essere "globali" all'applicazione, ad esempio la connection string per accedere ad un database, oppure l'URL per connettersi ad un web service. Queste impostazioni sono generalmente memorizzate nel file app.config associato all'applicazione.
Il metodo Save() della classe ApplicationSettingsBase permette solamente il salvataggio delle impostazioni "User Scoped" (a livello di utente), lasciando le impostazioni "Application Scoped" di sola lettura.
Ho trovato due modi per modificare e salvare le impostazioni di validità globale; supponendo di voler modificare l'impostazione WebServiceUrl, si può:
1. Utilizzare la classe ConfigurationManager per modificare direttamente la sezione AppSettings del file app.config
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings["WebServiceUrl"].Value = "http://server/WebServices/Service1.asmx";
config.Save(ConfigurationSaveMode.Modified);
2. Estendere il LocalFileSettingsProvider in modo che possa persistere anche le impostazioni a livello di applicazione:
public
class MyLocalFileSettingsProvider : LocalFileSettingsProvider
{
private bool IsApplicationSetting(SettingsProperty setting)
{
return setting.Attributes[typeof(ApplicationScopedSettingAttribute)] is ApplicationScopedSettingAttribute;
}
private string GetSectionName(SettingsContext context)
{
string groupName = (string)context["GroupName"];
string settingsKey = (string)context["SettingsKey"];
string result = groupName;
if (!string.IsNullOrEmpty(settingsKey))
{
result = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", result, settingsKey);
}
return XmlConvert.EncodeLocalName(result);
}
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection values)
{
// Nome del file di configurazione
string configFileName = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath;
// Nome della sezione che contiene le impostazioni
string sectionName = this.GetSectionName(context);
// Caricamento del file di configurazione XML
XmlDocument doc = new XmlDocument();
doc.Load(configFileName);
// Impostazione dei nuovi valori, se modificati
foreach (SettingsPropertyValue value in values)
{
if (IsApplicationSetting(value.Property) && value.IsDirty)
{
string XPathValue = string.Forma(@"//configuration/applicationSettings/{0}/setting[@name=""{1}""]/value/text()", sectionName, value.Property.Name);
doc.SelectSingleNode(XPathValue).Value = (string)value.SerializedValue;
}
}
// Salvataggio delle modifiche sul file di configurazione
doc.Save(configFileName);
base.SetPropertyValues(context,values);
}
}
In questo secondo caso, dovremo informare la nostra classe di settings che il suo contenuto dovrà essere persistito tramite il nostro nuovo provider.
[SettingsProvider(typeof(MyLocalFileSettingsProvider))]
public sealed class MySettings : ApplicationSettingsBase
{
[ApplicationScopedSetting]
public string WebServiceUrl
{
get { return (string)this["WebServiceUrl"]; }
set { this["WebServiceUrl"] = value; }
}
}
Ora è possibile scrivere una cosa del tipo:
MySettings sett = new MySettings();
sett.WebServiceUrl = "http://server/WebServices/Service1.asmx";
sett.Save();
e salvare anche l'impostazione "Application Scoped".
Bisogna tenere presente che la modifica dell'app.config è riservata generalmente ai membri del gruppo Administrators, quindi è sempre bene verificare i permessi dell'utente corrente prima di salvare le impostazioni.