4

我们有一个在 App_Code 中实现中央 HttpSessionState 管理的网站,如下所示:

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();
    }
}

所有这些工作都很好,直到我们需要在一个新线程中实现一个耗时的过程......在第二个线程中 HttpContext.Current.Session 为空(我们知道它是因为当前上下文在线程之间不同)所以一切都失败了: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");
    }
 }

我们想要做的是将会话关联到新线程(CurrentSession.Session = mySession;),因此每个函数都按原样工作而不更改它们(有很多,我们不想为此更改应用程序的所有结构最后添加)但 HttpContext.Current.Session 没有设置器:S(我们知道我们必须将设置器添加到 CurrentSession.Session 属性)

那么……你会怎么解决呢?有什么绝妙的技巧吗?我们的一个想法是将 CurrentSession.Session 转换为动态指针或类似的东西,因此当我们要在第二个线程内使用函数时,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;
       }
    }
}

所以这就是历史......很抱歉让这篇文章这么长,但我们想弄清楚情况以防止混淆和偏离答案......谢谢!

4

2 回答 2

2

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

于 2011-01-31T21:13:04.183 回答
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为 a ProgramSession(构造函数应涵盖此)并将ProgramSession对象传递给您的线程。这样,您的应用程序和线程将针对相同的接口而不是相同的实现工作。

这不仅应该解决您的问题,而且使测试更加容易,因为您的线程不再依赖于HttpSessionState. 现在,当测试你的线程时,你可以传入任何实现该ISession接口的类。

于 2011-01-31T19:46:11.047 回答