4
\$\begingroup\$

I have a Table that I store All setting in that , it is like below :

public  class Setting:IEntity
{
    public string Key { get; set; }
    public string Value { get; set; }
}

and I have a service like this to update and read Setting Table :

   public class SettingService : ISettingService
{

    #region Fields

    private readonly IUnitOfWork _uow;
    private readonly IDbSet<Setting> _settings;

    private static readonly ConcurrentDictionary<string, object> _cash = new ConcurrentDictionary<string, object>();

    #endregion

    #region Methods


    #region ctor

    public SettingService(IUnitOfWork uow)
    {
        _uow = uow;
        _settings = _uow.Set<Setting>();
        if (_cash.IsEmpty)
            lock (_cash)
            {
                if (_cash.IsEmpty)
                    _settings.ToList().ForEach(item => _cash.TryAdd(item.Key, item.Value));
            }
    }

    #endregion

    public T Get<T>() where T : ISetting
    {
        object value;
        var setting = Activator.CreateInstance<T>();
        var prefix = typeof(T).Name;

        foreach (PropertyInfo item in typeof(T).GetProperties())
        {
            string key = $"{prefix}.{item.Name}";

            _cash.TryGetValue(key, out value);
            if (item.PropertyType == typeof(Boolean))
            {
                bool result;
                Boolean.TryParse(value?.ToString(), out result);
                item.SetValue(setting, result);
            }
            else
                item.SetValue(setting, value);
        }
        return setting;
    }

    public void Set<T>(T model) where T : ISetting
    {
        var prefix = typeof(T).Name;
        Type type = typeof(T);

        foreach (PropertyInfo prop in typeof(T).GetProperties())
        {

            var key = $"{prefix}.{prop.Name}";
            var setting = _settings.FirstOrDefault(row => row.Key == key);
            var isAddedd = true;
            if (setting == null)
            {
                setting = new Setting { Key = key };
                _settings.Add(setting);
                _uow.MarkAsAdded(setting);
                isAddedd = false;
            }

            setting.Value = prop.GetValue(model, null)?.ToString() ?? string.Empty;
            if (isAddedd)
                _uow.MarkAsChanged(setting);
            _cash.AddOrUpdate(key, setting.Value, (oldkey, oldValue) => setting.Value);
        }

    }

    #endregion
}

I use this Service Like below :

var data = _settingService.Get<AboutSetting>(); // when I want to featch from db
     _settingService.Set<AboutSetting>(aboutUsViewModel);// for update

now I need to Read All Project Setting from project , in some Views I need just some of them like Address , Tel ,...

I have created some Classes Like below :

public static class CompanyConfig
{
    private static CompanyInformationSetting _companySettings;
    private static ISettingService _settingService;

    static CompanyConfig()
    {
        _settingService = ApplicationObjectFactory.Container.GetInstance<ISettingService>();
        _companySettings = _settingService.Get<CompanyInformationSetting>();

    }

    public static string CompanyAddress
    {
        get { return _companySettings.Address; }
    }
}

and use them in View Like :

 <h2> Address : @(CompanyConfig.CompanyAddress) </h2>

Is there a way better than this , does this way bad for Performance ?

Another Way is to change BaseViewPage Like below and set some properties like below :

public class BaseViewPage<TModel> : WebViewPage<TModel>
{
    private readonly ISettingService _settingService;
    public BaseViewPage()
    {
        _settingService = ApplicationObjectFactory.Container.GetInstance<ISettingService>();
    }

    public override void Execute()
    {
    }

    public string CompanyName
    {
        get { return _settingService.Get<CompanyInformationSetting>("CompanyName"); }
    }

    public string CompanyPhoneNumber
    {
        get { return _settingService.Get<CompanyInformationSetting>("PhoneNumber"); }
    }
    public string CompanyEmail
    {
        get { return _settingService.Get<CompanyInformationSetting>("Email"); }
    }
    public string CompanyAddress
    {
        get { return _settingService.Get<CompanyInformationSetting>("Address"); }
    }

}

in this way we dont need to static class and it solves singleton of UnitOfwork

\$\endgroup\$
  • \$\begingroup\$ updated post , I've add another way \$\endgroup\$ – work question Aug 19 '17 at 5:58
4
\$\begingroup\$

Quick note first, _cash should be _cache dictionary definition:

a temporary storage space or memory that allows fast access to data

Is this bad for performance?

You'd have to measure it but you've got a non-trivial amount of reflection on every call to Get and Set. Why not serialize your values to JSON or Xml to store in the database? Create an interface and you can decide on your implementation later. You could test a bunch of serializers and see which is fastest.

public interface ISettingSerializer
{
    string Serialize<T>(T value);
    T Deserialize<T>(string value);
}

What I'm really trying to say is: don't create your own serialization. There are already multiple good options that support a lot of configuration. E.g. think about attributes to control how or even whether a member is included.


You have another problem - a captive dependency.

You have a Singleton CompanyConfig (as it's static) that holds a reference to a unit of work (through the settings service) which shouldn't be kept alive for the lifetime of the application IMO.

\$\endgroup\$
  • \$\begingroup\$ thank you . I've got another Idea , to put Setting.josn file in Project Root and when project start at first read settings from database and put them in json file . \$\endgroup\$ – work question Aug 19 '17 at 5:27
  • \$\begingroup\$ updated post , I've add another way \$\endgroup\$ – work question Aug 19 '17 at 5:58
  • 1
    \$\begingroup\$ @workquestion - I've done similar to your update in the past and think it's a good way to go. \$\endgroup\$ – RobH Aug 19 '17 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.