2010-11-25 59 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

重构代码可能会更好地服务于您。让你的函数实际上接受它们操作的参数,而不是依赖数据在环境中(在会话中)。如果你有一个需要知道当前用户是谁的功能,那么告诉它当前用户是谁。