Graciously Hosted by MaximumASP        

Global Application settings and the web.config file.

While getting started on .NETOOP, one of the first issues to address is that of “Global” settings.

When you build a web application for a single purpose, you can hard-code things without much concern.

Microsoft.com is probably always going to have the same name, but .NETOOP is going to be a portal application. Everyone who uses the application will need to .NETOOP to use their own web site name (and lots of other site specific configuration data.)

Now ASP.NET has that clever “Application Settings” feature. This is a great feature that includes design time setting creating and a well factored API for reading the settings.

The problem is that these settings like “Site Name” are going to be used all over the site and the actual settings are stored in the web.config file.

Reading the .xml file several times for each page lifecycle would be VERY bad for performance.

By the way, if your worried about WRITING to the web.config file, you are right. When you save changes to a web.config file the application needs to be reset, so you defiantly do not want to do much writing to the web.config file since it will kill performance and screw up session state for in session users.

In our case we are talking about global configuration settings which will be set up when the site is originally configured and will very seldom, if ever, be changed after deployment. So the write issue is a moot point for our requirements but the READ FREQUENCY is still a big issue.

As we’re building .NETOOP we really want to take advantage of ASP.NET services, but we want the application to scale VERY well.

At first I thought perhaps the right solution was to implement a new Settings Provider that uses SQL Server as described [ HERE ]

We’ll probably have to revisit the custom provider when we implement profiles but it seemed over kill for our needs and I think I’ve implemented a better solution with less work.

Innate property caching !

Given the application settings in the following web.config snippet……

  <appSettings>
    <add key="SiteName" value="NETOOP Site Name" />
    <add key="SiteOwner" value="NETOOP Site Owner" />
  </appSettings>

We need a way for the values to be accessible and not have that access degrade performance.

Now, one of the things you may be thinking is that an application object may be a great place for this kind of data.

I’ve opted NOT to use an Application scoped object because there is a certain usage scenario that is ill-served by this.

Example: The “Title” and “MetaData” of each page should be unique and dynamic, but should include the data from the Application Setting.

So, here is my solution ….

First, a static class to contain the site’s global settings.

using System;
using System.Web;
using System.Web.Configuration;
 
/// <summary>
/// SiteGlobalSettings is used to "cache" settings that are used globally and frequently
/// and are stored in the applications settings section of the web.config file.
/// This was the web.config file does not have to be read from disk each time a 
/// "Site Wide Setting' needs to be accessed. 
/// When changes are made to the web.config file, the appdomain will be reset so the 
/// static constructor will be run when the application restarts and the new values will 
/// be retrieved. 
/// </summary>
public static class SiteGlobalSettings
{
    static public string MySiteName { get; set; }
    static public string MySiteOwner { get; set; }
 
 
	static SiteGlobalSettings()
	{
  
         MySiteName = WebConfigurationManager.AppSettings.Get("SiteName");
         MySiteOwner = WebConfigurationManager.AppSettings.Get("SiteOwner");
 
	}
}
 

This means that these values will be retrieved when the application receives it’s FIRST request for a page that uses this class, the constructor is only called ONCE, which means the web.config files only needs to be accessed once, and the class’s static properties stay in memory in between page requests.

Now I can use the global settings like this……

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
 
public partial class _Default : System.Web.UI.MasterPage
{
    protected void Page_Load(object sender, EventArgs e)
    {
 
        if (null != SiteGlobalSettings.MySiteName)
            Page.Header.Title = SiteGlobalSettings.MySiteName;
        else
            Page.Header.Title = "NETOOP - The .NET Object Oriented Portal";
     
        
    }
}
 

Those this code is simply using the value from the web.config file as is, I could be appending some page specific data (and I will as I implement .NETOOP). I could also declare the page title as a static variable at the page level to improve performance even more.

Share your thoughts with me !!!

 

» Similar Posts

  1. Trapping Intentional Cross Site Scripting (XSS) Attempts in ASP.NET
  2. .NETOOP Global Statics Update
  3. Session Time Out Tricks

» Trackbacks & Pingbacks

  1. Thank you for submitting this cool story - Trackback from DotNetShoutout

  2. Pingback from Global Application settings and the web.config file. : Misfit Geek

  3. Pingback from Global Application settings and the web.config file. | I love .NET!

  4. Pingback from Global Application settings and the web.config file. | Nexo IT - Information Technology News

  5. Pingback from Global Application settings and the web.config file. | Nexo IT - Information Technology News

  6. Pingback from Global Application settings and the web.config file. : Misfit Geek

  7. Thank you for submitting this cool story - Trackback from ravipendigg

  8. Pingback from The Technology Post for July 6th, 2009 | I love .NET!

  9. Pingback from The Technology Post for July 6th, 2009 | Nexo IT - Information Technology News

  10. Pingback from The Technology Post for July 6th, 2009 | rapid-DEV.net

  11. I don’t claim to be the best developer on the planet :) but I’m always amazed at how all the “experts” come out of the woodwork to posh on other peoples code :) Several folks have commented and emailed about hey the technique I posted earlier was unnecessary

» Comments

  1. Muhammad Mosa avatar

    I just wanted to highlight something about the settings! few things should not be considered as settings! such as site name, which here demonstrated to be used as Site Title. This string could be localized. And so it should be stored in some other proper place and not in configuration.

    Just to highlight the difference between settings and localizable literals that can be confused with settings.

    Muhammad Mosa — July 6, 2009 9:44 AM
  2. Darnell avatar

    Well, that's your OPINION.

    Darnell — July 6, 2009 9:46 AM
  3. Johnny avatar

    Excellent post Joe. Totally agree on that approach right there. For those settings in web.config that we hardly ever change a static class is the better solution.

    Cheers

    Johnny — July 6, 2009 10:18 AM
  4. Henrik Juhlin avatar

    Whoaa... I’m impressed. I have always been thinking of web.config of a good place to put stuffs like this and that is was cached in memory or something. But after some tests I did, I have found out that this is about 10-15 times faster for each read. And that’s for every read, so doing this for example “for (int i = 0; i < 10000000; i++) { Page.Header.Title = WebConfigurationManager.AppSettings.Get("SiteName"); }”

    takes 15 sec! Doing the same with your version takes 0.3 sec. Getting the value one time form web.config takes 00:00:00.0000181 and one time from your version takes 00:00:00.0000011

    But then I can’t understand why the web.config settings isnt cached. Guess it’s the same for connection strings, and they are often used on all pages and on some pages more the once.

    Henrik Juhlin — July 6, 2009 10:47 AM
  5. Subbaraokv avatar

    Great article ! I have a question though, how do we address the encryption and decryption of key value data that we store in appSettings

    Subbaraokv — July 6, 2009 11:39 AM
  6. Richard avatar

    @Henrik

    I always believed as you that .config settings are cached as this article <http://msdn.microsoft.com/en-us/library/aa719558(VS.71).aspx> on the MSDN site indicates (the item is under .NET Framework 1.1 so the assumption is that MS did not "uncache" the settings in a subsequent framework version). I have seen elsewhere that web resources are not cached when debug="true" is set in web.config. I was curious how the debug flag was set during your tests and if you have tried the same tests with the debug flag set to both true and false to see if there is any difference?

    Richard — July 6, 2009 12:17 PM
  7. Henrik Juhlin avatar

    @Richard

    I did have it at <compilation debug="false"> before and tested to change it do true now. Page.Header.Title = WebConfigurationManager.AppSettings.Get("SiteName"); stayed the same, but the Page.Header.Title = SiteGlobalSettings.MySiteName; did go up a with like 30%, but still, the SiteGlobalSettings are around 7-8 times faster.

    Henrik Juhlin — July 6, 2009 1:39 PM
  8. Bernie Basel avatar

    I'm interested in the decision not to use application variables for this type of data. On my site I have code in the Global.asax that iterates though the AppSettings and create corresponding application variables at application start up. What does creating a static class buy you over the use of application variables?

    Bernie Basel — July 6, 2009 3:43 PM
  9. Johnny Nouel avatar

    Now I have a question:

    How long does that little Settings class is being kept in cache before it goes to read again from web.config file in disk?

    Johnny Nouel — July 6, 2009 3:46 PM
  10. Joe Stagner avatar

    Johnny - The Static Class will stay in memory as long as the application does. When the application is removed from memory depends on the application, app pool, and IIS configureations but asa rule of thumb, it will be unloaded after 20 minutes with NO requests.

    Joe Stagner — July 6, 2009 4:54 PM
  11. Joe Stagner avatar

    Bernie,

    There are a couple of reasons that I choose not to use Application Object.

    Yhere might be quite a bit of data and Application Objects use Name/Value pairs.

    I don't care for this style, types are not obvious, using user defined types are un-intuitive and lookup for very frequently accessed data items would cause a performance hit since the item needs to be located in the Applacation object collection before it's value can be retrieved.

    Also, for SEO purposes I intend to use some of these values as root values and add some semi-static page specific data.

    Joe Stagner — July 6, 2009 5:02 PM
  12. Bernie Basel avatar

    By definition data retrieved from the Web.Config will be strings data. But I understand, I do some processing in the Application start like converting the connection string into a ConnectionString object. I was not aware of a performance hit using Name/Value pairs as opposed to retrieving a value from an object but it makes sense. I guess like most things I should create a test bed and take some timings.

    Bernie Basel — July 6, 2009 5:46 PM
  13. Joe Stagner avatar

    Bernie,

    One of the key points is that non string data will only be accessed ONCE as string data when retrieved form the config file but once stored as a static property it can be a member variable of any type.

    Joe Stagner — July 6, 2009 5:49 PM
  14. Lee Dumond avatar

    I kinda have to agree with the first comment.

    While there may be many values that this approach may be useful for, I would look into localization for storing string literals, rather than configuration.

    Lee Dumond — July 6, 2009 6:15 PM
  15. Joe Stagner avatar

    This is a single sample. There are many data items that may not be localizable. Agin, use the technique if it meets your needs,do something else if it doesn't.

    Joe Stagner — July 6, 2009 6:18 PM
  16. Varun avatar

    Nice approach Joe. Carry on, thanks.

    Varun — July 7, 2009 4:39 AM
  17. Adam Schroder avatar

    I've been using the static variables approach with great success. Beats trying to put a wrapper around the Application variables or directly accessing the Application settings with magic strings.

    What do you guys do with user specific variables? Store them in the session?? retrieve them from the db when needed??

    Adam Schroder — July 7, 2009 7:19 AM
  18. vijay avatar

    Hi Joe,

    I have couple of questions to you. Assuming that we would not update the web.config file programmatically is there need for SiteGlobalSettings class. Because my understanding is that even the web.config file is cached when the application is loaded. Correct me if I am wrong.

    Do we need to check for null for each and every property acceess from SiteGlobalSettings class.

    Why are you hardcoding the "NETOOP - The .NET Object Oriented Portal" text in the else part. Should we throw an exception instead.

    Thanks,

    Vijay.

    vijay — July 7, 2009 8:44 AM
  19. Joe Stagner avatar

    Hi Vijay,

    1.) My test showed the static value is faster. (plus all theother reasons I listed above.)

    2.) Yes

    3.) Becuase it's a prototype

    Joe Stagner — July 7, 2009 8:46 AM
  20. Andy White avatar

    I think you are over engineering it.

    Andy White — July 7, 2009 4:51 PM
  21. Raj Kaimal avatar

    >Reading the .xml file several times for each page lifecycle would be VERY bad for performance.

    Are you sure about this? I thought web.config was cached.

    From MSDN:

    ...

    ...

    These methods perform read-only operations, use a single ***cached*** instance of the configuration, and are multithread aware.

    http://msdn.microsoft.com/en-us/library/system.web.configuration.webconfigurationmanager(VS.80).aspx

    Regards,

    Raj

    Raj Kaimal — July 7, 2009 4:53 PM
  22. Henrik Juhlin avatar

    @Raj I was sure about that to until I did a few tests:

    This takes 15 sec to run:

    for (int i = 0; i < 10000000; i++)

    {

    Page.Header.Title = WebConfigurationManager.AppSettings.Get("SiteName");

    }

    Doing the same with the static class takes 0.3 sec

    Henrik Juhlin — July 7, 2009 6:14 PM
  23. RN avatar

    First of All: Doesnt make sense to provide a Setter in the property.

    Second: It would be much easier to just add the static variable in a helper class, instead of creating a seperate class.

    public static HelperClass

    {

    public static string AppSetGetValue = ConfigurationManager.AppSettings["Name"];

    }

    Since Static variables will be initialized only once.

    Hope this helps..

    Thanks,

    RN

    RN — July 7, 2009 9:00 PM
  24. Vijay avatar

    Joe,

    I dont think it is a good idea to check for null for each property access in SiteGlobalSettings class for the following reasons.

    1. There is no guarantee that every developer will check for null.

    2. We have to wirte more code.

    Instead i am suggesting the following strategy.

    public static class SiteGlobalSettings

    {

    static private string mySiteName;

    static public string MySiteName

    {

    get

    {

    if(null != mySiteName)

    return mySiteName;

    else

    throw Exception("Site name not set.");

    }

    set

    {

    mySiteName = value;

    }

    }

    static SiteGlobalSettings()

    {

    mySiteName = WebConfigurationManager.AppSettings.Get("SiteName");

    }

    }

    This way we don't have to check for null for each propery access. We can simply call SiteGlobalSettings.MySiteName.

    Thanks,

    Vijay.

    Vijay — July 8, 2009 9:38 AM
  25. Jaymz avatar

    Vijay,

    You would still need to check for null's in your example, as you're just throwing the exception, so you'd need to handle that exception at the location you're accessing the property.

    You're method would work if instead of throwing it up, you return a valid value. So for strings, instead of returning null, you return String.Empty.

    Depends on your situation and what kind of developers you have I suppose.

    Jaymz — July 8, 2009 11:55 AM
  26. Jack avatar

    Lots applications and dlls use the application setting, NETOOP is the same and easy to master ;)

    Jack — July 9, 2009 4:18 AM
  27. Martin avatar

    I think you need to do a bit more investigation.

    It does make sense to deal with some items like this, and it's handled reasonably well, so kudos. However, your assumption that the web.config settings are not cached because they take longer to return is not necessarily valid. As others have pointed out, the MSDN documentation states that they are cached.

    One reason it might take longer to return items via the AppSettings accessor is that it's using a dictionary rather than a direct reference to a variable.

    Martin — July 9, 2009 5:32 AM
  28. Joe Stagner avatar

    web.config settings ARE cached when NOT runnign in debug mode, but still much slower as per the tests in the otherpots.

    Joe Stagner — July 9, 2009 8:33 AM
  29. Joseph avatar

    Joe,

    Would this be an ideal way to create a reference to an object to be used application wide instead of instantiating it whenever a method is needed? Such as the ProductBLL in the example here: www.asp.net/.../tutorial-02-vb.

    Thanks,

    Joseph

    Joseph — July 9, 2009 4:25 PM
  30. Joe Stagner avatar

    Hi Joseph,

    It might, but it really depends on your application. I suggest you restrict "global" ojects to those that will be widely and freqently used since they use memory.

    Remember, this object is STATIC (every user doesn't create a copy.)

    Joe Stagner — July 10, 2009 7:14 AM
  31. Dave Erwin avatar

    Thanks for the info. Great post. Just did a variation in a Winforms app to grab the db connection strings from appsettings into a static class. Always wondered how much caching was going on and what the performance impact would be. Haven't had time to measure it but it made a visible difference.

    Dave Erwin — July 10, 2009 7:54 AM
  32. Anatoliy avatar

    Another helpful thing can be to storing settings out of web.config. I'm point settings section to another file and it work with native .NET config accessors and doesn't cause restarting of application when settings changed. In this case instead of putting list of properties inside web.config we just need to write something like this:

    <appSettings configSource="settings.config"/>

    Extending your class with file FileSystemWatcher will be universal solution even for dynamic data.

    Anatoliy — July 11, 2009 6:21 AM

Comments are closed