Serialzation of settings

Topics: Core, General, Writing modules
Aug 11, 2015 at 12:48 PM
Edited Aug 15, 2015 at 12:44 PM
Can the loading and saving of settings be done in a dictionary? Right now as far as I have seen, the following is possible:
Model.Settings.APropertyName.PropertyMetaInformation.PropertyFilterDisplaySettings.Active
But what I would need is to store settings in a dictionary like this:
Model.Settings.PropertyMetaInformation[APropertyName].PropertyFilterDisplaySettings.Active
So is this possible?


.------------------------------

Explanation:

I have many parts like this:
public partial class DescriptionPart : ContentPart<DescriptionPartRecord> {
        
        #region Fields and Properties

        public string DescriptionShort {
            get { return Retrieve(r => r.DescriptionShort); }
            set { Store(r => r.DescriptionShort, value); }
        }
        
        public string DescriptionLong {
            get { return Retrieve(r => r.DescriptionLong); }
            set { Store(r => r.DescriptionLong, value); }
        }
        
        #endregion
        
    }
Now in order to implement a search page I want to store settings for each property, e.g. if it should be searchable or how it should be displayed. So I guess the best way is to follow the tutorial at Defining settings for Content Types and store settings for each property at the part. I want to be able to store meta-information like this:
public class PropertyMetaInformation {
        public string PropertyName { get; set; }
        public Type PropertyType { get; set; }
        public PropertyFilterDisplaySettings PropertyFilterDisplaySettings { get; set; }
    }

    public class PropertyFilterDisplaySettings {
        public bool Active { get; set; }
        public PropertyFilterDisplay PropertyFilterDisplay { get; set; }
        public IEnumerable<dynamic> PropertyFilterDisplay_AvailableModes { get; set; }
    }
This works fine as long as I have a class like "DescriptionPartSettingsPropertyFilter" that I have to hard code the values for each setting:
public class DescriptionPartSettings : AbstractContentPartSettings {
        
        public DescriptionPartSettings() {
            AbstractPropertyFilter = new DescriptionPartSettingsPropertyFilter(this);
        }
        
        public override Type ContentPartType {
            get {
                return typeof(DescriptionPart);
            }
        }
        
        public DescriptionPartSettingsPropertyFilter PropertyFilter {
            get {
                return (DescriptionPartSettingsPropertyFilter) AbstractPropertyFilter;
            }
        }
That following class I would like to drop because it is the same as the part properties anyway:
    public class DescriptionPartSettingsPropertyFilter : AbstractPropertyFilter {
        
        public DescriptionPartSettingsPropertyFilter(AbstractContentPartSettings abstractContentPartSettings)
            : base(abstractContentPartSettings) {
            
            DescriptionShort = new PropertyFilterDisplaySettings();
            DescriptionLong = new PropertyFilterDisplaySettings();
        }
        
        public PropertyFilterDisplaySettings DescriptionShort { get; set; }
        public PropertyFilterDisplaySettings DescriptionLong { get; set; }
        
    }
}
However, I would like to get rid of the class above and use a dictionary instead:
public class GeneralContentPartSettings {

        public abstract Type ContentPartType { get; }

        protected Type ContentPartSettingsHookType {
            get {
                return Assembly.GetExecutingAssembly().GetType(ContentPartType.Name + "SettingsHooks");
            }
        }

        protected object ContentPartExample {
            get {
                return Activator.CreateInstance(ContentPartType);
            }
        }

        protected object ContentPartSettingsHookExample {
            get {
                return Activator.CreateInstance(ContentPartSettingsHookType);
            }
        }

        public Dictionary<string, PropertyInfo> PropertyReflectionInfo {
            get {
                Dictionary<string, PropertyInfo> propertyMetaInfo = new Dictionary<string, PropertyInfo>();

                foreach (PropertyInfo partSettingsProperty in ContentPartType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) {
                    propertyMetaInfo.Add(partSettingsProperty.Name, partSettingsProperty);
                }

                return propertyMetaInfo;
            }
        }

        Dictionary<string, PropertyMetaInformation> propertyMetaInfo = new Dictionary<string, PropertyMetaInformation>();

        public Dictionary<string, PropertyMetaInformation> PropertyMetaInformation {
            get {
                if (propertyMetaInfo.Count == 0) {
                    foreach (PropertyInfo partSettingsProperty in PropertyReflectionInfo.Values) {
                        propertyMetaInfo.Add(partSettingsProperty.Name,
                            new PropertyMetaInformation {
                                PropertyName = partSettingsProperty.Name,
                                PropertyType = partSettingsProperty.PropertyType,
                                PropertyFilterDisplaySettings = new PropertyFilterDisplaySettings(),
                            });
                    }
                }

                return propertyMetaInfo;
            }
        }
    }
Deserializing nearly seems to work (if you debug and do step-overs in Visual Studio) but serialzation does not (values do not get stored) because of the dictionary instead of normal properties, I guess:
public partial class DescriptionPartSettingsHooks : GeneralPartSettingsHooks {

        public override Type PartInfoType {
            get { return typeof(DescriptionPart); }         
        }

        public override Type SettingsType {
            get { return typeof(DescriptionPartSettings); }         
        }
    }
public partial class GeneralPartSettingsHooks : ContentDefinitionEditorEventsBase {
         
         public virtual Type PartInfoType {
            get { return null; }            
        }

         public virtual Type SettingsType {
            get { return null; }            
        }

        private string GetSettingPatternPrefixFor(string propertyName) {
            return PartInfoType.Name + ".PropertyMetaInformation[" + propertyName + "].PropertyFilterDisplaySettings";
        }


        public Localizer T { get; set; }

        public override IEnumerable<TemplateViewModel> TypePartEditor(ContentTypePartDefinition definition) {
            if (definition.PartDefinition.Name != PartInfoType.Name) {
                yield break;
            }
            
            IEnumerable<MethodInfo> openMethods = definition.Settings.GetType().GetMethods().Where(x =>(x.GetParameters().Count() == 0 && x.Name == "GetModel"));
            MethodInfo openMethod = openMethods.single();
            MethodInfo toInvoke = openMethod.MakeGenericMethod(typeof(SettingsType));
            dynamic model = toInvoke.Invoke(definition.Settings, null);

            #region Load setting values

            foreach (PropertyMetaInformation setting in model.PropertyMetaInformation.Values) {               
                setting.PropertyFilterDisplaySettings.PropertyFilterDisplay_AvailableModes = Enum.GetValues(typeof(PropertyFilterDisplay))
                .Cast<int>()
                .Select(i =>
                    new {
                        Text = Enum.GetName(typeof(PropertyFilterDisplay), i),
                        Value = i
                    });
            }

            #endregion

            yield return DefinitionTemplate(model);
        }

        public override IEnumerable<TemplateViewModel> TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) {
            if (builder.Name != PartInfoType.Name) {
                yield break;
            }

            dynamic model = Activator.CreateInstance(SettingsType);

            if (updateModel.TryUpdateModel(model, SettingsType.Name, null, null)) {

                #region Save setting values

                foreach (PropertyMetaInformation setting in model.PropertyMetaInformation.Values) {
                    builder.WithSetting(GetSettingPatternPrefixFor(setting.PropertyName) + ".Active", (setting.PropertyFilterDisplaySettings.Active).ToString(CultureInfo.InvariantCulture));
                    builder.WithSetting(GetSettingPatternPrefixFor(setting.PropertyName) + ".PropertyFilterDisplay", ((int)setting.PropertyFilterDisplaySettings.PropertyFilterDisplay).ToString(CultureInfo.InvariantCulture));
                }

                #endregion

            }

            yield return DefinitionTemplate(model);
        }

    }
}

So, in simple words out-of-the-box the loading of settings can be done using
Model.Settings.APropertyName.PropertyMetaInformation.PropertyFilterDisplaySettings.Active
but what I would need is to store settings in a dictionary:
Model.Settings.PropertyMetaInformation[APropertyName].PropertyFilterDisplaySettings.Active