Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding how Nop Commerce settings are loaded from the database

I am working with Nop Commerce and wondering if someone can please help me with my confusion.

I have debugged the code many times trying to find out how the settings are loaded on start up of the web application. I just don't get it!

All settings classes implement the ISettings interface. Lets take customer settings for example.. I have found out that it is represented by the CustomerSettings class. In the database there is a Setting table. Data for customer settings looks somethng like this:

customersettings.usernamesenabled
customersettings.checkusernameavailabilityenabled
customersettings.allowuserstochangeusernames
... and so on...

How and where are each of these settings mapped from customersettings to the CustomerSettings class and a property like usernamesenabled mapped to the UsernamesEnabled property in the CustomerSettings class? And why was it implemented this way?

I know it has something to do with the following code in the DependencyRegistrar class:

builder.RegisterGeneric(typeof(ConfigurationProvider<>)).As(typeof(IConfigurationProvider<>));
builder.RegisterSource(new SettingsSource());

If someone can point me in the right direction then it would be appreciated.

like image 581
Brendan Vogt Avatar asked May 19 '12 16:05

Brendan Vogt


1 Answers

Hope i'm not late.

There are only a few relevant points to look at to understand how that structure is created:

-Nop.Services.Configuration.ConfigurationProvider class
-Nop.Services.Configuration.ISettingsService interface
-Nop.Services.Configuration.SettingsService class

The SettingsService only provides functionality to store and retrieve settings from the repositories, and implements some caching functionality.

The ConfigurationProvider does the actual magic.

Let's look at the BuildConfiguration method:

        // get properties we can write to
        var properties = from prop in typeof(TSettings).GetProperties()
                         where prop.CanWrite && prop.CanRead
                         let setting = _settingService.GetSettingByKey<string>(typeof(TSettings).Name + "." + prop.Name)
                         where setting != null
                         where CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).CanConvertFrom(typeof(string))
                         where CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).IsValid(setting)
                         let value = CommonHelper.GetNopCustomTypeConverter(prop.PropertyType).ConvertFromInvariantString(setting)
                         select new { prop, value };

Using reflection, *Settings class (for example, CustomerSettings), are inspected and their properties used to load corresponding settings from the service.

Then it converts back the value stored as string (you can check the NopCustomTypeConverter to see how the serialization happens) and assign them back to the Setting Entity:

properties.ToList().ForEach(p => p.prop.SetValue(Settings, p.value, null));

The other method, SaveSettings(TSettings settings) does the exact opposite, takes a Setting entity and breaks it down, generating keys-value pairs in the form of ClassName+Propertyvalues)

It was implemented like this because it deploys concepts from IoC, segregation of interfaces, n-tier and other patterns to ensure maintainability (API based componentization, testability ecc).

like image 138
WDRust Avatar answered Oct 10 '22 02:10

WDRust