我一直在阅读ASP.Net中的单身人士,我已经看到了各种实现和建议。我试图在这个之后对我的实现进行建模:https://stackoverflow.com/...asp-net-singleton
这是我的问题:我希望我实例化的对象持续当前会话的生命,但不会在会话之间共享。例如,如果两个用户同时登录,我希望他们每个“拥有”一个全局对象的实例。以下是我的实施。这是正确的方法吗?
public class AppGlobal
{
#region Contructors
public AppGlobal() { }
public static AppGlobal Instance
{
get
{
HttpSessionState session = HttpContext.Current.Session;
if (session["AppGlobalInstance"] == null)
{
session["AppGlobalInstance"] = new AppGlobal();
}
return (AppGlobal)session["AppGlobalInstance"];
}
}
#endregion
#region Public Properties
public User UserObject { get; set; }
public Campaign CampaignObject { get; set; }
public List<int> SelectedContactIDs = new List<int>();
public List<int> UnsubmittedContactIDs = new List<int>();
public List<int> SubmittedContactIDs = new List<int>();
public List<int> ProcessedContactIDs = new List<int>();
#endregion
#region Public Instance Methods
public void ClearCampaign()
{
CampaignObject = null;
UnsubmittedContactIDs.Clear();
SubmittedContactIDs.Clear();
ProcessedContactIDs.Clear();
SelectedContactIDs.Clear();
}
public void LoadCampaign(int campaignID)
{
//Ensure that old data is overwritten
MailCampaignManagerEntities db = new MailCampaignManagerEntities();
db.Campaigns.MergeOption = System.Data.Objects.MergeOption.OverwriteChanges;
//Clear the campaign and associated data
ClearCampaign();
//Set campaign object in AppGlobal
this.CampaignObject = db.Campaigns.SingleOrDefaultasp.net(x => x.CampaignID == campaignID);
//Populate Contact Status Lists
this.UnsubmittedContactIDs.AddRange(from x in this.CampaignObject.CampaignContacts
where x.ContactSubmissionID == null
select x.CampaignContactID);
this.SubmittedContactIDs.AddRange(from x in this.CampaignObject.CampaignContacts
where x.ContactSubmissionID != null
select x.CampaignContactID);
this.ProcessedContactIDs.AddRange(from x in this.CampaignObject.CampaignContacts
where x.ContactSubmissionID != null
&& x.ContactSubmission.DateProcessed != null
select x.CampaignContactID);
}
#endregion
#region Public Static Methods
public static void WriteLogEntry(int? campaignID, int? contactSubmissionID, int? scheduledDropID, int? userID, string activityDescription)
{
ActivityLog activityLog = new ActivityLog();
activityLog.CampaignID = campaignID;
activityLog.ContactSubmissionID = contactSubmissionID;
activityLog.ScheduledDropID = scheduledDropID;
activityLog.UserID = userID;
activityLog.Text = activityDescription;
activityLog.CreatedDate = DateTime.Now;
using (MailCampaignManagerEntities db = new MailCampaignManagerEntities())
{
db.ActivityLogs.AddObject(activityLog);
db.SaveChanges();
}
}
#endregion
}
答案 0 :(得分:2)
实施通常应该是“好的”,但是......
您应该将对象标记为[Serializable]
,具体取决于您已配置的SessionStateModule。 Web场或Web园通常使用modules other than the InProc one,它们使用序列化来存储会话状态。否则,您的对象看起来可以序列化,所以没有问题。
您可能想要检查当前是否有任何会话,或者您可以获得NullReferenceException
。这可能意味着应用程序配置错误,或者在生命周期中过早地调用。
由于您检查和设置Session变量的方式存在竞争条件,您的应用程序可能会为单个会话分配两次AppGlobal对象。我不认为即使这是目前的问题,但如果你想要包含更多花哨的东西,请记住这一点。为了防止这种情况,您可以像这样使用lock
:
public class AppGlobal
{
private static object _syncRoot = new object();
public static AppGlobal Instance
{
get
{
HttpSessionState session = HttpContext.Current.Session;
lock (_syncRoot)
{
if (session["AppGlobalInstance"] == null)
{
session["AppGlobalInstance"] = new AppGlobal();
}
}
return (AppGlobal)session["AppGlobalInstance"];
}
}
}
如果您想在禁止序列化的对象中存储任何内容,并且需要支持其他SessionStateModule,则可以将实例存储在使用经典Singleton模式的集合中(here是一个很好的实现) 。 ConcurrentDictionary可能是个好人。作为关键,您可以使用您在会话中执行存储的独特内容,例如GUID。当会话以任何方式结束时,您需要从集合中删除条目。
答案 1 :(得分:0)
这看起来像一个有效的单例模式。它看起来像是一个非常大的对象存储在Session中。如果您有很多用户,可能会遇到性能和内存问题。
答案 2 :(得分:0)
Session
中的对象已经是唯一的,这意味着同一个键指的是一个对象实例。
答案 3 :(得分:0)
Session对象基本上来自单例对象的字典。因此,当您引用Session对象时,您已经从场景背后的单例模式中受益。因此,您不需要通过将Session对象放入单例模式来重新发明轮子。