views:

311

answers:

3

I'm developing a blog application shared by non-profit organizations. I want each organization to be able to change their own blog settings. I have taken a singleton pattern (from BlogEngine.net) and modified it. (I understand that it is no longer a singleton pattern.) I have tested this approach and it seems to work fine in a development environment. Is this pattern a good practice? Are there issues, which may arise when this is placed in a production environment?

public class UserBlogSettings
    {
    private UserBlogSettings()
    {
        Load();
    }

    public static UserBlogSettings Instance
    {
            get
            {
                string cacheKey = "UserBlogSettings-" + HttpContext.Current.Session["userOrgName"].ToString();
                object cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
                if (cacheItem == null)
                {
                    cacheItem = new UserBlogSettings();
                    HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, DateTime.Now.AddMinutes(1),
                                             Cache.NoSlidingExpiration);
                }
                return (UserBlogSettings) cacheItem;
            }
    }
}    

(Portions of code were omitted for brevity.)

Thanks for any help, comment, etc.

+5  A: 

If its per session, store it in the Session and not in the Cache.

Also, you're upcasting and downcasting for no reason here:

object cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;

this removes the unneeded casts

UserBlogSettings cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
if (cacheItem == null)
{
    cacheItem = new UserBlogSettings();
    HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, 
                         DateTime.Now.AddMinutes(1),
                         Cache.NoSlidingExpiration);
}
return cacheItem;
Will
It's by user organization (as opposed to user) -- so organization xyz may have many users on the site at the same time view their blog.
Geri Langlois
@geri That makes more sense. Other than the cast issue its not bad. You sure you only want to cache it for a minute? Consider the lifetime of the object when creating/inserting it into the cache.
Will
Thanks for the casting suggestion -- the one minute cache is for development only. What about the static instance? Any problems with that?
Geri Langlois
@Geri nope, as long as you don't declare any type-scoped static variables you touch/modify from within your static method.
Will
Thanks Will -- appreciate all your time and help.
Geri Langlois
A: 

I think your is good in general, but I would suggest a performance enhancement if it becomes necessary (I know... don't optimize until you really need to).

I would probably implement this with a method like this to get the settings object:

public static UserBlogSettings getSettings(string orgName, Cache cache) {
  // do the same stuff here, except using the method parameters
}

The reason for this is that HttpContext.Current and HttpRuntime.Cache have to go through some gyrations to get handles to the current Session and Cache. If you are calling this from an asp.net page, you already have that stuff in hand. So use the ones you already have rather than looking them up again.

Ray
+3  A: 

You need to use locking to avoid possible race conditions:

    private static Object lock_Instance = new Object ();
    public static UserBlogSettings Instance 
    { 
        get 
        { 
            string cacheKey = "UserBlogSettings-" + HttpContext.Current.Session["userOrgName"].ToString(); 
            UserBlogSettings cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
            if (cacheItem == null) 
            {
                lock (lock_Instance)
                {
                    // need to check again in case another thread got in here too
                    cacheItem = HttpRuntime.Cache[cacheKey] as UserBlogSettings;
                    if (cacheItem == null)
                    {
                        cacheItem = new UserBlogSettings();
                        HttpRuntime.Cache.Insert(cacheKey, cacheItem, null, 
                            DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration);
                    }
                }
            } 
            return cacheItem; 
        } 
    } 
ZaijiaN