2011-05-20 38 views
1

私はASP.Netでシングルトンについて読んできましたが、私はさまざまな実装や提案を見てきました。 https://stackoverflow.com/...asp-net-singletonASP.Netセッションでの静的なシングルトン

ここに私の質問があります:私は現在のセッションの生存期間をインスタンス化しているが、セッション間で共有されていないオブジェクトを希望します。たとえば、2人のユーザーが同時にログインしている場合、グローバルオブジェクトのインスタンスをそれぞれ「所有する」ようにします。以下は私の実装です。これを行うには適切な方法ですか?

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

実装は通常、「大丈夫」にする必要がありますが、...

あなたが設定したSessionStateModuleに応じて、[Serializable]としてオブジェクトをマークする必要があります。 WebファームまたはWebガーデンは通常modules other than the InProc oneを使用し、シリアル化を使用してセッション状態を格納します。それ以外の場合は、あなたのオブジェクトがシリアル化されるように見えるので、問題はありません。

現在セッションがあるかどうかを確認したり、NullReferenceExceptionを取得したりできます。しかし、これはおそらく、誤って設定されたアプリケーション、またはライフサイクルの早すぎる呼び出しを意味します。

アプリケーションは、Session変数の確認と設定の競合状態により、1回のセッションでAppGlobalオブジェクトを2回割り当てることがあります。私はそれが現在問題ではないと思っていますが、もっと上品なものを含めることを忘れないでください。それを防ぐために、あなたはこのような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をサポートする必要がある場合古典的なシングルトンパターン(hereは良い実装です)。 ConcurrentDictionaryはおそらく良いでしょう。キーとして、GUIDのようにセッションにdoを格納するというユニークなものを使用できます。セッションが終了すると、コレクションからエントリを削除する必要があります。

+0

冗長な回答をいただきありがとうございます。 –

0

これは有効なシングルトンパターンのようです。また、Sessionに格納するための非常に大きなオブジェクトのように見えます。多くのユーザーがいる場合は、パフォーマンスとメモリの問題に遭遇する可能性があります。

0

Sessionのオブジェクトはすでに一意であり、同じキーがオブジェクトの1つのインスタンスを参照することを意味します。

0

セッションオブジェクトは、基本的にはシングルトンオブジェクトの辞書に由来します。したがって、Sessionオブジェクトを参照すると、シーンの後ろにあるシングルトンパターンの恩恵を受けることになります。したがって、セッションオブジェクトをシングルトンパターンに配置することによってホイールを再作成する必要はありません。

関連する問題