2010-11-25 33 views
4

我們有一個網站,它實現了在App_Code文件這樣的中央HttpSessionState管理:從另一個線程或技巧訪問HttpSessionState(HttpContext.Current.Session)?

public static class CurrentSession 
{ 
    public static HttpSessionState Session 
    { 
     get 
     { 
      return HttpContext.Current.Session; 
     } 
    } 

    public static bool Exists 
    { 
     get 
     { 
      return Session != null ? true : false; 
     } 
    } 
    public static ControlUsu user 
    { 
     get 
     { 
      return (ControlUsu)Session["currentuser"]; 
     } 

     set 
     { 
      Session["currentuser"] = value; 
     } 
    } 
    public static OdbcConnection connection 
    { 
     get 
     { 
      return (OdbcConnection)Session["currentconnection"]; 
     } 
     set 
     { 
      Session["currentconnection"] = value; 
     } 
    } 
    public static OdbcCommand command 
    { 
     get 
     { 
      return (OdbcCommand)Session["currentcommand"]; 
     } 
     set 
     { 
      Session["currentcommand"] = value; 
     } 
    } 
    public static DataTable datatable 
    { 
     get 
     { 
      return (DataTable)Session["currentdatatable"]; 
     } 
     set 
     { 
      Session["currentdatatable"] = value; 
     } 
    } 
    public static OdbcDataAdapter dataadapter 
    { 
     get 
     { 
      return (OdbcDataAdapter)Session["currentdataadapter"]; 
     } 
     set 
     { 
      Session["currentdataadapter"] = value; 
     } 
    } 
    public static Table tablatemp 
    { 
     get 
     { 
      return (Table)Session["tablatemp"]; 
     } 
     set 
     { 
      Session["tablatemp"] = value; 
     } 
    } 

    public static void Init() 
    { 
     user= new ControlUsu(); 
     connection= new OdbcConnection(); 
     command= new OdbcCommand(); 
     datatable = new DataTable(); 
     dataadapter = new OdbcDataAdapter(); 
     tablatemp = new Table(); 
     //SessionActual.conexion.ConnectionTimeout = 0; 
    } 
} 

功能類,使用它(例如):

public class Funx 
{ 
    public DataTable QuerySQLDT(string SQLx) 
    { 
     try 
     { 
      CurrentSession.connection.Open(); 
     } 
     catch (Exception ex) 
     { 
      ServicioTecnico.EnviarMailError("Error openning connection", ex); 
      HttpContext.Current.Response.Redirect("SesionExpirada.aspx", true); 
     } 
     try 
     { 
      CurrentSession.command.CommandText = SQLx; 
      CurrentSession.dataadapter.SelectCommand = SessionActual.command; 

      CurrentSession.datatable.Clear(); 
      CurrentSession.datatable.Reset(); 
      CurrentSession.dataadapter.Fill(SessionActual.datatable); 

      CurrentSession.connection.Close(); 
     } 
     catch (Exception ex) 
     { 
      try 
      { 
       CurrentSession.connection.Close(); 
      } 
      catch { } 
      try 
      { 
       ex.Data.Add("SQLx", SQLx); 
       ServicioTecnico.EnviarMailError("Error closing connection", ex); 
      } 
      catch { } 
      throw; 
     } 

     return CurrentSession.datatable.Copy(); 
    } 
} 

所有這一切都工作得很好ultil我們需要在一個新的線程中實現一個耗時的過程...... 在第二個線程中HttpContext.Current.Session爲null(我們知道它是因爲當前上下文其線程之間不同)所以一切都失敗了:S

調查我們發現,你可以從一個線程通過會話到另一個像這樣:

using App_Code; 
public partial class Example: Page 
{ 
    private void startoperation 
    { 
     Session["savedsession"] = HttpContext.Current.Session; 
     ThreadStart operation = delegate { buscar(); }; 
     Thread thread = new Thread(operation); 
     thread.Start(); 
    } 
    private void longoperation 
    { 
     HttpSessionState mySession = ((HttpSessionState)Session["savedsession"]); 
     //what we would like to do 
     //CurrentSession.Session = mySession; 

     Funx fun=new Funx(); 
     DataTable resul=Funx.QuerySQLDT(select * from exampletable"); 
    } 
} 

我們希望做的是asociate會話到新的線程(CurrentSession.Session = MySession的;)所以每函數按原樣工作而不改變它們(有很多,我們不想改變最後一個應用程序的所有結構),但HttpContext.Current.Session沒有setter:S(我們知道我們必須添加setter到我們的CurrentSession.Session屬性)

那麼...你會如何解決它?任何好的技巧? 我們想到的一個想法是將CurrentSession.Session轉換爲dinamic指針或類似的東西,所以當我們打算使用第二個線程中的函數時,CurrentSession.Session的getter將從爲該案例傳遞的臨時變量返回會話線程的...但我們沒有一個明確的想法如何實現它?一個可能的草案是:

public static class CurrentSession 
{ 
    public static HttpSessionState magicpointer; 

    public static HttpSessionState Session 
    { 
     get 
     { 
      //return HttpContext.Current.Session; 
      return magicpointer; 
     } 
     set 
     { 
      magicpointer=value; 
     } 
    } 
} 

public partial class Example : Page 
{ 
    bool completedtask=false; //we know this would be Session variable or so to work with threads 
    private void startoperation 
    { 
     Session["savedsession"] = HttpContext.Current.Session; 
     ThreadStart operation = delegate { buscar(); }; 
     Thread thread = new Thread(operation); 
     thread.Start(); 
    } 
    private void longoperation 
    { 
     HttpSessionState mySession = ((HttpSessionState)Session["savedsession"]); 

     CurrentSession.Session = mySession; 
     //or set the magicpointer...whatever works... 
     CurrentSession.magicpointer= mySession; 

     Funx fun=new Funx(); 
     DataTable resul=Funx.QuerySQLDT(select * from exampletable"); 

     //time consuming work... 

     completedtask=true; //change the flag so the page load checker knows it... 
    } 
    private void page_load_checker() 
    { //this combined with javascript that makes the page postback every 5 seconds or so... 
     if(completedtask) 
     { 
      //show results or something like that 
      //set the CurrentSession.magicpointer or CurrentSession.Session 
      //to point the HttpContext.Current.Session again... 
      CurrentSession.magicpointer=HttpContext.Current.Session; 
     } 
    } 
} 

所以這就是歷史...抱歉讓這個帖子這麼長時間,但我們希望清楚瞭解情況以防止混淆和偏離的答案......謝謝!

+0

這個想法是有一箇中央集合的函數(我們以後做了一個函數庫,以便在任何Web項目中輕鬆使用它)將處理數據庫請求,當前用戶變量等......但不必傳遞每個變量從方法到方法,從頁面到頁面,從線程到線程...... – VSP 2012-03-02 08:49:25

+0

我們願意改變所有的結構,但目標是讓它像現在一樣容易使用這些功能,而不是更糟糕。 – VSP 2012-03-02 08:51:08

回答

1

您可以創建一個界面。

public interface ISession 
{ 
    public ControlUsu user {get; set;} 
    public OdbcConnection connection {get; set;} 
    //Other properties and methods... 
} 

然後你可以有兩個類來實現它。

//Use this class when you have HttpSessionState 
public class ProgramHttpSession : ISession 
{ 
    public ControlUsu user 
    { 
     get {return (ControlUsu)Session["currentuser"];} 
     set {Session["currentuser"] = value;} 
    } 
    public OdbcConnection connection 
    { 
     get {return (OdbcConnection)Session["currentconnection"];} 
     set {Session["currentconnection"] = value;} 
    } 
} 

//Use this class when you DON'T have HttpSessionState (like in threads) 
public class ProgramSession : ISession 
{ 
    private ControlUsu theUser; 
    public ControlUsu user 
    { 
     get {return theUser;} 
     set {theUser = value;} 
    } 

    private OdbcConnection theConnection; 
    public OdbcConnection connection 
    { 
     get {return theConnection;} 
     set {theConnection = value;} 
    } 

    public ProgramSession(ControlUsu aUser, OdbcConnection aConnection) 
    { 
     theUser = aUser; 
     theConnection = aConnection; 
    } 
} 

讓你的線程類以ISession作爲參數。當您創建或開始線程時,將ProgramHttpSession轉換爲ProgramSession(構造函數應該覆蓋此)並將ProgramSession對象傳遞給您的線程。這樣,你的應用程序和線程將在相同的接口上工作,但不是相同的實現。

這不僅應該解決您的問題,而且要讓測試更容易,因爲您的線程不再依賴於HttpSessionState。現在當測試你的線程時,你可以傳入任何實現了這個接口的類。

+0

這將工作,但仍然需要重構有問題的所有方法/類以使用`ISession` – Basic 2011-01-31 21:16:58

2

重構代碼可能會更好地服務於您。讓你的函數實際上接受它們操作的參數,而不是依賴數據在環境中(在會話中)。如果你有一個需要知道當前用戶是誰的功能,那麼告訴它當前用戶是誰。