开发者

Is this modified C# singleton pattern a good practice?

开发者 https://www.devze.com 2022-12-19 11:44 出处:网络
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

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.C开发者_如何学运维urrent.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.

0

精彩评论

暂无评论...
验证码 换一张
取 消