Laden...

ConfigurationSection lässt sich nicht aktualisieren

Letzter Beitrag vor 8 Jahren 12 Posts 3.163 Views
ConfigurationSection lässt sich nicht aktualisieren

Hallo,
ich verwende diese Methode um auf eine Section zuzugreifen:


        public static SettingsSection GetSection()
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            return config.GetSection("Settings") as SettingsSection ?? new SettingsSection();   
        }

Beim Schließen des Fensters wird dann folgende Methode zum Speichern verwendet:


        private void SaveSettings()
        {   
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (config.Sections["Settings"] == null) config.Sections.Add("Settings", Settings);
            config.Save(ConfigurationSaveMode.Full);
        }

Das erste Speichern und Laden klappt ohne Probleme. Wenn ich die Section jedoch lade und ändere, wird nichts neues geschrieben, sondern die alten Werte bleiben einfach bestehen. Woran kann das liegen?

Hi R3turnz,

eventuell mußt du die SectionInformation.AllowOverride-Eigenschaft auf true setzen. Ansonsten gibt es u.a. ein funktionierenes Beispiel in der Doku zur Configuration-Klasse.

Weeks of programming can save you hours of planning

Nein, das ist nicht der Grund.

@R3turnz:
Du hast dir mal genau durchgelesen was ConfigurationUserLevel.None bedeutet?
Das bedeutet das die Config aus dem Anwendungsverzeichnis benutzt wird, und die ist readonly ( aus gutem Grund ).

Willst du eine Speicherbare Config haben, kann es nur entweder die PerUserRoamingAndLocal oder PerUserRoaming sein.

Wenn ich den ConfigurationUserLevel auf PerUserRoaming setze wird folgende Exception geworfen:> Fehlermeldung:

InnerException:
HResult=-2146233079
Message=Die ConfigurationSection-Eigenschaften können nicht bearbeitet werden, wenn sie gesperrt sind.
Source=System.Configuration
StackTrace:
bei System.Configuration.SectionInformation.VerifyIsEditable()
bei System.Configuration.SectionInformation.set_AllowExeDefinition(ConfigurationAllowExeDefinition value)
bei OpenWeather.GUI.ViewModel.SaveSettings() in ...\ViewModel.cs:Zeile 153.

Kurzes googeln hat ergeben, dass ich folgende Eigenschaft setzen muss:


Settings.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToRoamingUser;

Dies führt zur gleichen Exception, jetzt aber beim setzen der Eigenschaft.

Dir fehlt auch

   Settings.SectionInformation.AllowExeDefinition =   
                 ConfigurationAllowExeDefinition.MachineToLocalUser;

Ich verstehe dich nicht ganz, ich habe die Eigenschaft doch schon gesetzt. Ich öffnemit PerRoaming und dafür wird doch nur eigentlich diese Option gedacht. Aber auch dein Vorschlag führt ändert nichts an dem Fehler.

Ich hatte - warum auch immer - übersehen, dass Du Settings.SectionInformation.AllowExeDefinition schon gefunden hast.

Zeig mal bitte den vollständigen Quellcode bei Deinen Settings.
SectionInformation muss vor dem Section.Add erfolgen.

So raten wir im Prinzip nur, was Du da aktuell hast.
Das frustriert Dich und bringt uns nicht weiter 😉

Ich sehe niregnds, wie und wo denn diese geänderten Daten der neuen Config-Instanz bekannt gemacht werden. Und was die nicht kennt, kann die auch nicht speichern. 😁

Hallo R3turnz,

zu dem von Sir Rufo gesagtem:

Ich hab das glaube vor Ewigkeiten mal mit:

 Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);

config.AppSettings.Settings["MyValue"].Value = "Asdasdasd";

config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("appSettings");

gemacht.

Gruss

Coffeebean

Hier der komplette Quellcode:


 class SettingsSection : ConfigurationSection, INotifyPropertyChanged
    {
        #region fields
        static ConfigurationPropertyCollection _properties;
        static ConfigurationProperty _location;
        static ConfigurationProperty _tempUnit;
        #endregion
        #region constructors
        static SettingsSection()
        {
            _properties = new ConfigurationPropertyCollection();
            _location = new ConfigurationProperty("Location", typeof(LocationElement), new LocationElement());
            _tempUnit = new ConfigurationProperty("unit", typeof(ClimaticData.TemperatureUnit));
            _properties.Add(_location);
            _properties.Add(_tempUnit);
        }
        #endregion
        #region properties
        public LocationElement Location
        {
            get
            {
                return base[_location] as LocationElement;
            }
            set
            {
                base[_location] = value;
                OnPropertyChanged(nameof(Location));
            }
        }
        public ClimaticData.TemperatureUnit TempUnit
        {
            get
            {
                return (ClimaticData.TemperatureUnit)base[_tempUnit];
            }
            set
            {
                base[_tempUnit] = value;
                OnPropertyChanged(nameof(TempUnit));
            }
        }
        protected override ConfigurationPropertyCollection Properties
        {
            get { return _properties; }
        }
        #endregion
        #region INotifyPropertyChanged members
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
        #region methods
        public static SettingsSection GetSection()
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
            return config.GetSection("Settings") as SettingsSection ?? new SettingsSection();   
        }
        #endregion
    }
    class LocationElement : ConfigurationElement, IDataErrorInfo, INotifyPropertyChanged
    {
        [ConfigurationProperty("city")]
        public string City
        {
            get
            {
                return base["city"] as string;
            }
            set
            {
                base["city"] = value;
                OnPropertyChanged(nameof(City));
            }
        }
        [ConfigurationProperty("country")]
        public string CountryCode
        {
            get
            {
                return base["country"] as string;
            }
            set
            {
                base["country"] = value;
                OnPropertyChanged(nameof(CountryCode));
            }
        }
        [ConfigurationProperty("latitude")]
        public double Latitude
        {
            get
            {
                return (double)base["latitude"];
            }
            set
            {
                base["latitude"] = value;
                OnPropertyChanged(nameof(Latitude));
            }
        }
        [ConfigurationProperty("longitude")]
        public double Longitude
        {
            get
            {
                return (double)base["longitude"];
            }
            set
            {
                base["longitude"] = value;
                OnPropertyChanged(nameof(Longitude));
            }
        }
        #region IDataErrorInfo members
        public new string this[string columnName]
        {
            get
            {
                string error = string.Empty;
                if (columnName == nameof(City))
                {
                    if (string.IsNullOrEmpty(City)) error = "City cannot be empty!";
                }
                else if (columnName == nameof(Latitude))
                {
                    if (!IsValidCoordinate(Latitude)) error = "The coordinate is out of range!";
                }
                else if (columnName == nameof(Longitude))
                {
                    if (!IsValidCoordinate(Longitude)) error = "The coordinate is out of range!";
                }
                return error;
            }
        }
        public string Error
        {
            get { throw new NotImplementedException(); }
        }
        #region INotifyPropertyChanged members
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
        #endregion
        #region private methods
        private bool IsValidCoordinate(double coordinate)
        {
            return coordinate >= -180 && coordinate <= 180;
        }
        #endregion
        #region methods
        public bool IsValidColumn(string columnName)
        {
            return string.IsNullOrEmpty(this[columnName]);
        }
        #endregion
    }

Code zum Speichern und Laden:


        public static SettingsSection GetSection()
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
            return config.GetSection("Settings") as SettingsSection ?? new SettingsSection();   
        }
             private void SaveSettings()
            {   
                var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
                Settings.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
                if (config.Sections["Settings"] == null) config.Sections.Add("Settings", Settings);
                config.Save(ConfigurationSaveMode.Full);
                ConfigurationManager.RefreshSection("Settings");
            }

Ich habe Sir Rufos Vermuting im Debugger überprüft und tatsächlich werden die Werte nicht synchronisiert. Der Indexer der Sections Collection ist aber schreibgeschützt, wie sind diese synchronisieren? (@Coffebean Ich gehe davon aus, dass du RefreshSection meinst? Ändert leider nichts)

Hallo

ich glaube eher, dass Sir Rufo meint, dass du die config ausliest und wieder speicherst. Du weist nirgends die neuen Werte zu.

private void SaveSettings()
            {
                var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
                Settings.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
                if (config.Sections["Settings"] == null) config.Sections.Add("Settings", Settings);
                config.Save(ConfigurationSaveMode.Full);
                ConfigurationManager.RefreshSection("Settings");
            }

Wo kommt "Settings" her? Das fügst du ja nur an, wenn die config bisher keine Settings hat, oder nicht? 🤔

Hab mein (sehr altes) Codebeispiel mal gerade in ner Console probiert und es funktioniert einwandfrei bei mir. Hast du mal probiert das Problem in einem Mini-Projekt nachzustellen? Dass du mal ein Projekt hast mit dem du die config speichern kannst. Und das dann portierst?

Gruss

Coffeebean

Ich habe gerade ein wenig herumprobiert und bin auf eine doch sehr naheliegende Lösung gekommen. Das Configuration Objekt, welches zum Speichern und Laden verwendet wird muss das gleiche sein, dann werden auch die Werte synchronisiert:


private static readonly Configuration _config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
Settings = _config.GetSection("Settings") as SettingsSection ?? new SettingsSection();
        private void SaveSettings()
        {
            Settings.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
            if (_config.Sections["Settings"] == null) _config.Sections.Add("Settings", Settings);
            _config.Save(ConfigurationSaveMode.Full);
        }

Die GetSection Methode in der ConfigurationSection zu impelementieren, ist also nur für den lesenden Zugriff geeignet:


        public static SettingsSection GetSection()
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoaming);
            return config.GetSection("Settings") as SettingsSection ?? new SettingsSection();   
        }

(@Coffebean Settings ist eine Eigenschaft, die per Datenbindung editiert wird)