Вопрос

I added a Settings.settings file to my project using the Properties > Settings dialog. I created a new configuration element with the type being a custom type. The output of the auto-generated code is as follow:

[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::Moslem.Model.Configuration.ApplicationConfiguration AppConfig
{
    get 
    {
        return ((global::Moslem.Model.Configuration.ApplicationConfiguration)(this["AppConfig"]));
    }
}

So far, that is fine. By default, all settings with ApplicationScopedSettingAttribute are read-only. Therefore I cannot simply initiate it elsewhere in the application. Obviously any use of any property of the ApplicationConfiguration object will throw a NullReferenceException.

My questions:

  1. Is there a standard way to initiate all the objects with application scope?
  2. Is it safe to simple write my own constructor and initiate the objects? (since Properties.Settings is auto-generated as partial)
Это было полезно?

Решение 2

I found the quickest way to initiate it when the application start however the values needs to be reloaded from the database. I created a new file with a partial class definition. All I had to do was to initialize the property hidden field:

namespace Application.Web.Properties
{
    public sealed partial class Settings
    {
        Settings()
        {
            this["AppConfig"] = new ApplicationConfiguration();
        }
    }
}

I no longer get the NullReferenceException when I try something like:

Properties.Settings.Default.AppConfig.PageTitle = "My Application";
Properties.Settings.Default.AppConfig.Description = "Cool Application 2014";
Properties.Settings.Default.AppConfig.Author = "Moslem © 2014";

Другие советы

I don't know the answer to your second question, but is the way I have initialized settings values from a database query. I think this will match the lifecycle the runtime normally expects.

First, create a matching partial class implementation for your auto-generated settings class:

[SettingsProvider(typeof(CustomSettingsProvider))]
internal sealed partial class Settings : ApplicationSettingsBase 
{
    public Settings()
    {
        CustomSettingsProvider.UpdateCustomSettings += delegate(object sender, EventArgs e)
        {
            this.Reload();
        };
    }
}

The SettingsProvider attribute identifies the class that is the source of your settings.

The event handler is optional. It is a way you can force the settings to get reloaded at runtime, if the values change asynchronously.

Here is what the SettingsProvider looks like:

public partial class CustomSettingsProvider : System.Configuration.SettingsProvider, System.Configuration.IApplicationSettingsProvider
{
    // raise this event to cause the settings to be reloaded at runtime after initialization
    public static event EventHandler UpdateCustomSettings;

    public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
    {
        SettingsPropertyValueCollection result = new SettingsPropertyValueCollection();

        // the collection identifies properties to initialize
        foreach (SettingsProperty property in collection)
        {
            SettingsPropertyValue spv = new SettingsPropertyValue(property);

            // determine value...

            spv.PropertyValue = value;
            result.Add(spv);
        }

        return result;
    }
}

There are a few overridable methods in the base class, but most of the work in done in the GetPropertyValues method. The collection argument identifies the properties that need initialization, for each one look up the value, or provide some default value to avoid your NullReferenceExceptions.

We are using this technique for authorization settings. We have several modules in the application, each with a different set of authorization settings, but all are tied to the same CustomSettingsProvider.

The database code to read the settings is separate from the CustomSettingsProvider class, but accessible to the CustomSettingsProvider.GetPropertyValues method through a singleton interface. We added a public static method on the CustomSettingsProvider to raise the UpdateCustomSettings event (since the event and method are static, there is no event "sender", but the event arguments are not used anyway).

When the database query completes and the settings are read in, the static method is called on the CustomSettingsProvider class, which raises the UpdateCustomSettings event and in turn the Settings class invokes it's Reload method. The default Reload implmentation calls the GetPropertyValues method to re-initializes all the setting values with the new data from the database.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top