简体   繁体   中英

Is this modified C# singleton pattern a good practice?

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.

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;

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; 
        } 
    } 

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM