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.
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).