Share via


best way to store static values from a database to use globally?

Question

Monday, March 21, 2011 8:52 PM

Hello,

I need to load several values from a database that will be used thruout the website. For example: website name, website ID, etc.

I know I can load the values into Application variables like Application["WebsiteName"], Application["WebsiteID"], etc but I would rather have it in a static class since I read it perfforms better.

Is it possible to load data from a database into static class members?

I just need this data to be loaded once and it's the same for every user. Or are there other better ways to cache those values?

Thank you

All replies (10)

Wednesday, March 23, 2011 2:55 PM âś…Answered

Hello. since my settings are not many and are each setting is stored in a different table field, do you see a problem doint this way?

it seems to be working good.

 

 

public partial class Settings
{
    public static bool UseProducts { get; set; }
    public static int SiteID { get; set; }

    public static bool initialized;

    /// Constructor
    public Settings()
    {
        initialized = false;
    }

    /// Initializes the class
    public void Init()
    {
        if (!initialized)
            RetrieveAllSettings();
        initialized = true;
    }

    /// Loads all the settings from the db
    private void RetrieveAllSettings()
    {
        DataContext db = new DataContext();
        var settingval = (from s in db.websiteSettings
                          select s).SingleOrDefault();

        if (settingval != null)
        {
            UseProducts = settingval.UseProducts;
           SiteID= settingval.SiteID;
        }

    }


}

and on my global.asax:

void Application_BeginRequest(Object source, EventArgs e)
    {
        if (!Settings.initialized)
        {
            new Settings().Init();
        }
    }

thank you!

 


Monday, March 21, 2011 10:57 PM

Honestly there is no right answer to this type of request and there are many ways to do it.

One of the easiest is to load all your global settings from your database into your application state at the load of the application (or on first request) and have a class that inspects the application state.

Something like the following. (From one of my projects)

SQL Table

 

CREATE TABLE [dbo].[sys_Settings](
    [SettingID] [int] IDENTITY(1,1) NOT NULL,
    [Name] [varchar](100) NOT NULL,
    [Value] [varchar](max) NOT NULL,
    [Description] [varchar](1000) NULL,
 CONSTRAINT [PK_sys_Settings] PRIMARY KEY CLUSTERED 
(
    [SettingID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

 

Settings Class (using Linq)

 

public partial class Settings
    {
        /// <summary>
        /// internal settings
        /// </summary>
        private List<Data.sys_Setting> settings { get; set; }
        /// <summary>
        /// flag to demote already initialized
        /// </summary>
        private bool initialized;

        /// <summary>
        /// Constructor
        /// </summary>
        public Settings()
        {
            initialized = false;
        }

        /// <summary>
        /// Initializes the class
        /// </summary>
        public void Init()
        {
            if (!initialized)
                RetrieveAllSettings();

            initialized = true;
        }

        /// <summary>
        /// Loads all the settings then add the Current Settings class to the Http Application State
        /// </summary>
        private void RetrieveAllSettings()
        {
            settings = (from row in new DataObject().sys_Settings
                        select row).ToList();
            if (HttpContext.Current != null)
                HttpContext.Current.Application["resourceSettings"] = this;
        }

        /// <summary>
        /// Gets a setting By the Name and returns the Object Setting
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        public Data.sys_Setting GetSetting_ByName(string Name)
        {
            if (!initialized || settings.Count == 0)
                RetrieveAllSettings();
            return settings.Where(x => x.Name == Name).FirstOrDefault();
        }

        /// <summary>
        /// Gets a setting by the Setting ID and returns the Setting object
        /// </summary>
        /// <param name="SettingID"></param>
        /// <returns></returns>
        public Data.sys_Setting GetSetting_ByID(int SettingID)
        {
            if (!initialized || settings.Count == 0)
                RetrieveAllSettings();
            return settings.Where(x => x.SettingID == SettingID).FirstOrDefault();
        }

        /// <summary>
        /// Creates a setting By Name & Value
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Value"></param>
        /// <remarks>
        /// Calls CreateSetting(Name,Value,Description) with an empty description
        /// </remarks>
        public void CreateSetting(string Name, string Value)
        {
            CreateSetting(Name, Value, string.Empty);
        }

        /// <summary>
        /// Creates a setting with Name, Value & Description
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Value"></param>
        /// <param name="Description"></param>
        public void CreateSetting(string Name, string Value, string Description)
        {
            if (GetSetting_ByName(Name) != null)
                UpdateSetting(Name, Value);
            DataObject db = new DataObject();
            var setting = new Data.sys_Setting();
            setting.Name = Name;
            setting.Value = Value;
            setting.Description = Description;
            db.sys_Settings.InsertOnSubmit(setting);
            db.SubmitChanges();
            db.Dispose();
            RetrieveAllSettings();
        }

        /// <summary>
        /// Updates a setting, located the setting by name, then sets the Value to Value
        /// </summary>
        /// <param name="Name">The Name</param>
        /// <param name="Value">The Value</param>
        public void UpdateSetting(string Name, string Value)
        {
            if (GetSetting_ByName(Name) == null)
                CreateSetting(Name, Value);
            else
            {
                DataObject db = new DataObject();
                var setting = db.sys_Settings.SingleOrDefault(x => x.Name == Name);
                if (setting == null)
                    CreateSetting(Name, Value);
                setting.Value = Value;
                db.SubmitChanges();
                db.Dispose();
                RetrieveAllSettings();
            }
        }

        /// <summary>
        /// Resolves the Current Settings in the HTTP Context Application
        /// </summary>
        public static Settings Resolve
        {
            get
            {
                if (HttpContext.Current != null)
                    return (Settings)HttpContext.Current.Application["resourceSettings"];
                return null;
            }
        }
    }

 

Thats basically the class it has been "simplified" for this instance. Basically you call the Init() function which will retrieve all the settings and then store them into the Application State (HttpContext.Current.Applicatoin) providing this was initialized through a WebRequest of some sort.

Finally there is a static property at the end called Resolve. Because the Init actually stores the Settings Class (not the individual settings) into the HttpApplication the Static method retrieves the instance of the class to be called something like

 

public class Work
    {
        void work()
        {
            string Value = Settings.Resolve.GetSetting_ByName("sample.setting").Value;

        }
    }

 

Next the easiest way to call the Init method is in the Global.asax file such as.

 

            new Settings().Init();

 

Hope this helps point you in the right direction. Like I said there are many different ways to go about this

**Sorry for the update.. code highlighter issues


Tuesday, March 22, 2011 12:18 AM

Your best solution may be to put the settings in the AppSettings section of Web.Config.

http://weblogs.asp.net/stevewellens/archive/2011/01/15/web-config-is-cached.aspx


Tuesday, March 22, 2011 2:56 PM

Thank you, for the detailed script. Very good info!

So there is no way to do it with a static class?

Steve , the settings have to come from a database. Can't be web.config file.

Thank you

 

 


Tuesday, March 22, 2011 4:56 PM

You could use static classes if you like however I believe that in your instance you will be happier with a proper instantiatable class that has proper methods and properties. 

 

In the example provided i did add one static method that will resolve the instance of the class in the Application State. If you wanted to only have to call something like

Settings.Resolve.<SettingName>;

You could use reflection to call the setting by the method name something like

public string Setting { get { return GetSetting_ByName(MethodBase.GetCurrentMethod().Name.Replace("get_","")).Value; } set { Update_Setting(MethodBase.GetCurrentMethod().Name.Replace("set_",""), value) }}

But that will only work if you have a setting in your database named Setting and wont work for dynamic settings.


Wednesday, March 23, 2011 10:12 AM

Thank you, great info!

in my scenario the settings names are not dynamic. Only the values, so that would work.


Wednesday, March 23, 2011 5:01 PM

That should work fine except I would probably change one small thing (wont upset the calling)

Try changing

public static bool UseProducts { get; set; }
    public static int SiteID { get; set; }

To

private static bool useProducts;
        public static bool UseProducts
        {
            get { return useProducts; }
            set { useProducts = value; }
        }

        private static int siteID;
        public static int SiteID
        {
            get { return siteID; }
            set { siteID = value; }
        }

Otherwise you should be alright with your code.

 

Cheers


Wednesday, March 23, 2011 6:05 PM

That should work fine except I would probably change one small thing (wont upset the calling)

Try changing

Why?


Wednesday, March 23, 2011 6:31 PM

Good question, and to be honest his first implmentation was correct he doesnt need to add a private field\property.

However if you declare your variables with a private backing field (as OO practice) you expose yourself the ability to do validation, manipulation and allows you to declare more accurate results. Thus ensuring less errors during execution. Now in the instance i provided it has opened the OP to add personalization around the properties.

Try this for example

 

private static bool useDefault;
        public static bool UseDefaults
        {
            get
            {
                if (useDefault == null)
                    RetrieveSettings();
                return useDefault == null ? true : false;
            }
            set { useDefault = value; }
        }

 

Paul Linoton : you are correct in stating he doesnt actually need the private backing property, however in most instances some sort of validation on the getter and the setter should be fine.

Cheers


Saturday, July 7, 2012 11:02 AM

I was very happy to find this solution, and I've implemented it in my own MVC site.  However, I'm having a problem that perhaps you can help me with. 

For some reason, my Settings class (named AppSetting) is not getting instantiated at the Application Start level.

The code in the global.asax file is this:

        void Application_Start()
        {
            if (!AppSetting.initialized)
            {
                new AppSetting().Init();
            }
        }

I also run the Appsetting().Init() routine when I update the actual data in the database to update the static variables in Appsetting.  And that works fine, the changes to the static variables are made. Once I do that, anyone else visiting the site gets the appropriate info; but if the site isn't used for a few hours, the info gets lost again.

But I can't seem to get AppSetting().Init() to run at Application start.  And I'm getting no errors.

Anything you see that I'm missing?

I really do like this solution, and would prefer stay with the database structure, rather than using XML.