2011-05-20 3 views
1

Я читал о одиночных играх в ASP.Net, и я видел различные реализации и предложения. Я попытался смоделировать свою реализацию после этого: https://stackoverflow.com/...asp-net-singletonСтатический синглтон в сеансе ASP.Net

Вот мой вопрос: мне хотелось бы, чтобы объект, который я создавал, продолжал жизнь текущего сеанса, но не должен делиться между сеансами. Например, если два пользователя одновременно вошли в систему, я хочу, чтобы они каждый «собственный» экземпляр глобального объекта. Ниже приводится моя реализация. Это правильный способ сделать это?

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 
} 

ответ

2

Реализация обычно должно быть «хорошо», но ...

Вы должны пометить объект как [Serializable], в зависимости от SessionStateModule, что вы настроили. Веб-фермы или веб-сады обычно используют modules other than the InProc one, и они используют сериализацию для хранения состояния сеанса. В противном случае это выглядит нормально для вашего объекта, который будет сериализован, поэтому никаких проблем нет.

Возможно, вам захочется проверить, есть ли вообще какая-либо сессия, или вы можете получить NullReferenceException. Это, вероятно, означало бы неправильно сконфигурированное приложение или вызов слишком рано в жизненном цикле.

Приложение может распределять объект 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"]; 
     } 
    }  
} 

Если вы когда-либо хотите сохранить что-либо внутри объекта, который запрещает сериализации, и вы должны поддерживать другие SessionStateModules, вы можете хранить экземпляры в коллекции, которая использует классический шаблон Singleton (here - хорошая реализация). ConcurrentDictionary, вероятно, будет хорошим. В качестве ключа вы можете использовать что-то уникальное, которое вы используете и делаете на своем сеансе, как GUID. Вам нужно будет удалить запись из коллекции, когда сессия закончится каким-либо образом.

+0

Благодарим за подробный ответ и за фиксатор! –

0

Это похоже на действительный одноэлементный узор. Он также выглядит как очень большой объект для хранения в сеансе. Вы можете столкнуться с проблемами производительности и памяти, если у вас много пользователей.

0

Объекты в Session уже уникальны, что означает, что один и тот же ключ относится к одному экземпляру объекта.

0

Объект Session по существу состоит из словаря одиночных объектов. Таким образом, когда вы ссылаетесь на объект Session, вы уже пользуетесь синтаксическим шаблоном за сценой. Поэтому вам не нужно повторно изобретать колесо, помещая объект Session в одноэлементный шаблон.

Смежные вопросы