4

次のように、App_Code で中央の HttpSessionState 管理を実装する Web サイトがあります。

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

これはすべて、新しいスレッドで時間のかかるプロセスを実装する必要があった場合にうまく機能しました... 2 番目のスレッドでは、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");
    }
 }

私たちがやりたいことは、セッションを新しいスレッド (CurrentSession.Session = mySession;) に関連付けることです。そのため、すべての関数は変更せずにそのまま機能します (多くの関数があり、このためにアプリケーションのすべての構造を変更したくありません)。最後の追加) しかし、HttpContext.Current.Session にはセッターがありません:S (CurrentSession.Session プロパティにセッターを追加する必要があることはわかっています)

じゃあ…どうやって解決するの?何か素晴らしいトリックはありますか?私たちが持っていた 1 つのアイデアは、CurrentSession.Session を動的ポインターなどに変換することです。そのため、2 番目のスレッド内で関数を使用する場合、CurrentSession.Session のゲッターは、次の場合に渡された一時変数からセッションを返します。スレッド...しかし、それを実装する方法が明確にわかりません...可能なドラフトは次のようになります。

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...
}

次に、それを実装する 2 つのクラスを作成できます。

//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オブジェクトをスレッドに渡します。このようにして、アプリケーションとスレッドは同じインターフェースに対して動作しますが、同じ実装ではありません。

これは問題を解決するだけでなく、スレッドが に依存しなくなるため、テストがはるかに簡単になりますHttpSessionStateISessionこれで、スレッドをテストするときに、そのインターフェイスを実装する任意のクラスを渡すことができます。

于 2011-01-31T19:46:11.047 に答える