C# 从另一个线程访问HttpSessionState(HttpContext.Current.Session)还是从另一个线程访问?
我们有一个网站,它在App_代码中实现了中央HttpSessionState管理,如下所示:C# 从另一个线程访问HttpSessionState(HttpContext.Current.Session)还是从另一个线程访问?,c#,asp.net,multithreading,session,httpsession,C#,Asp.net,Multithreading,Session,Httpsession,我们有一个网站,它在App_代码中实现了中央HttpSessionState管理,如下所示: public static class CurrentSession { public static HttpSessionState Session { get { return HttpContext.Current.Session; } } public static bool Exists
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;
}
}
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");
}
}
使用它的函数类(例如):
所有这些都很好地工作,直到我们需要在一个新线程中实现一个耗时的进程。。。
在第二个线程中,HttpContext.Current.Session为null(我们知道它是空的,因为当前上下文在线程之间不同),因此所有操作都失败:S
调查发现,您可以将会话从一个线程传递到另一个线程,如下所示:
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;
}
}
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");
}
}
我们想做的是将会话关联到新线程(CurrentSession.session=mySession;),这样每个函数都可以按原样工作,而不会更改它们(有很多,我们不想为最后添加的内容更改应用程序的所有结构),但是HttpContext.Current.session没有setter:S(我们知道必须将setter添加到CurrentSession.Session属性)
那么…你怎么解决?有什么好办法吗?
我们的一个想法是将CurrentSession.Session转换为dinamic指针或类似的东西,因此当我们要在第二个线程中使用函数时,CurrentSession.Session的getter将从线程的情况下传递的临时变量返回会话…但我们不清楚如何实现它…可能的dra英国《金融时报》将是:
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;
}
}
}
这就是历史……很抱歉让这篇文章这么长时间,但我们想弄清楚情况,以防止混淆和偏离答案……谢谢!您可以创建一个界面
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
。现在,在测试线程时,您可以传入实现ISession
接口的任何类。重构代码可能会更好。您的函数实际上是否使用它们操作的参数,而不是依赖于(在会话中)周围的数据。如果你有一个功能需要知道当前用户是谁,那么告诉它当前用户是谁。+1这在短期内会非常痛苦,在长期内会非常有益。它简化了单元测试、IoC、依赖注入等。如果这是一个很好的主意,即使是远程可能的话。这会起作用,但仍然需要重构所有有问题的方法/类以使用ISession
问题是,在我们的例子中有很多方法和变量…并在这些情况下手动传递所有方法和变量+记住添加我们在会话中放入的每个新变量…:想法是有一组中心函数(我们后来制作了一个函数库,以便在任何web项目中轻松使用)将处理数据库请求、当前用户变量等…但无需将每个变量从一个方法传递到另一个方法、从一页传递到另一页、从一个线程传递到另一个线程…我们愿意更改所有结构,但目标是使这些函数与现在一样易于使用,而不是更糟。
public interface ISession
{
public ControlUsu user {get; set;}
public OdbcConnection connection {get; set;}
//Other properties and methods...
}