Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
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.