- PR -

ASP.NET セッション変数

投稿者投稿内容
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2005-09-11 12:05
このままやり取りを続けても堂々巡りになりそうな気がします。現象の再現する最低限のコード、およびUIの操作パターンを示す事は出来ませんか?

複数ユーザーで操作を行ったときにのみ発生するのであれば、他の方の言葉にもあるように「スレッドセーフに作られていない箇所が存在する」可能性が濃厚です。後は詳細なログを出力(随所でSessionIDとSessionの内容を保存すれば十分でしょう)して解析し、Session変数の変化する箇所を特定するぐらいしか、解決方法を思いつけません。

私もSession変数の内容が勝手に変化するとは信じていません。もし本当にSession変数の内容が勝手に変化していしまうとしたら、それは.NET Frameworkの持つ致命的なバグと言えるでしょう。

_________________
甕星 <mikahosi@abox9.so-net.ne.jp>
http://blogs.msmvp.jp/mikahosi/
ts12_
会議室デビュー日: 2005/09/05
投稿数: 10
投稿日時: 2005-09-11 18:04
長くなってしまいますが、該当部分のソースです。
(細かいエラー処理やメッセージ表示部分などは省略しました。)

●前提
 ユーザはログイン画面でユーザID、営業所コード、パスワードを入力する。
 ユーザはユーザID+営業所コードで一意に識別される

●ログイン画面
Imports System.Data
Imports System.Data.SqlClient

Public Class Login
Inherits System.Web.UI.Page

   ・
   ・

'<ログイン>ボタン押下
Private Sub cmdLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdLogin.Click
Dim DBConnect As New SqlConnection()
Dim DBReader As SqlDataReader

Dim strUName As String '担当者氏名
Dim strEigyo As String '営業所名
Dim strGrantCD As String '権限コード

Try
'データベースオープン
If funDBOpen(DBConnect) = False Then
Exit Sub
End If

'パスワードチェックとセッション変数に設定する情報を取得
If funLoginCheck(txtUserID.Text, txtEigyoCD.Text, txtPassword.Text, strUName, strEigyo, strGrantCD, DBReader, DBConnect) = False Then
Exit Sub
End If

'ユーザ情報をセッション変数に設定
Call subSetSession(txtUserID.Text, strUName, txtEigyoCD.Text, strGrantCD)

'一覧画面へ遷移
Call Response.Redirect("<遷移先URL>", False)

Catch
'エラー処理
Finally
' 'データベースクローズ
Call subDBClose(DBConnect)
End Try

End Sub



Function funLoginCheck(ByVal strUserID As String, _
ByVal strEigyoCD As String, _
ByVal strPassword As String, _
ByRef strUName As String, _
ByRef strEigyo As String, _
ByRef strGrantCD As String, _
ByRef DBReader As SqlDataReader, _
ByRef DBConnect As SqlConnection) As Boolean

funLoginCheck = False
Dim strSql As String

Try
'ユーザ名、パスワードを取得
strSql = "SELECT <ユーザ名>, <パスワード>"
strSql &= " FROM <ユーザテーブル>"
strSql &= " WHERE <ユーザID> = " & strUserID
strSql &= " AND <営業所ID> = " & strEigyoCD

'レコードオープン
If funRecOpen(strSql, DBReader, DBConnect) = False Then
Exit Function
End If

'存在確認
If DBReader.Read() = False Then
Exit Function
Else
'パスワードチェック
If DBReader("<パスワード>").ToString <> strPassword Then
Exit Function
Else
'ユーザ名
strUName = DBReader("<ユーザ名>").ToString

'レコードクローズ
Call subRecClose(DBReader)

'営業所名を取得
strSql = "SELECT <営業所名>"
strSql &= " FROM <営業所テーブル>"
strSql &= " WHERE <営業所ID> = " & strEigyoCD

'レコードオープン
If funRecOpen(strSql, DBReader, DBConnect) = False Then
Exit Function
End If

If DBReader.Read() = False Then
Exit Function
Else
'営業所名
strEigyo = DBReader("<営業所名>").ToString
End If

'レコードクローズ
Call subRecClose(DBReader)

'ユーザ権限を取得
strSql = "SELECT <ユーザ権限>"
strSql &= " FROM <ユーザ権限テーブル>"
strSql &= " WHERE <ユーザID> = " & strUserID
strSql &= " AND <営業所ID> = " & strEigyoCD

'レコードオープン
If funRecOpen(strSql, DBReader, DBConnect) = False Then
Exit Function
End If

If DBReader.Read() = False Then
Exit Function
Else
'ユーザ権限
strGrantCD = DBReader("<ユーザ権限>").ToString
End If
End If
End If

funLoginCheck = True

Catch
'エラー処理
Finally
'レコードクローズ
Call subRecClose(DBReader)
End Try

End Function


Sub subSetSession(ByVal strUserID As String, _
ByVal strUName As String, _
ByVal strEigyoCD As String, _
ByVal strEigyo As String, _
ByVal strGrantCD As String)

Session("<ユーザID>") = strUserID
Session("<ユーザ名>") = strUName
Session("<営業所ID>") = strEigyoCD
Session("<営業所名>") = strEigyo
Session("<ユーザ権限>") = strGrantCD


End Sub

End Class



●メニュー画面
Imports System.Data
Imports System.Data.SqlClient

Public Class Menu
Inherits System.Web.UI.Page

   ・
   ・

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' ページを初期化する ユーザー コードをここに挿入します。
Dim DBConnect As New SqlConnection()

Try
If Not IsPostBack Then
'データベースオープン
If funDBOpen(DBConnect) = False Then
Exit Sub
End If

'情報取得
If funGetInfo(DBConnect) = False Then
Exit Sub
End If

'ログインユーザを表示
txtTanto.Text = Session("<ユーザ名>").ToString
txtEigyo.Text = Session("<営業所名>").ToString
End If

Catch
'エラー処理
Finally
'データベースクローズ
Call subDBClose(DBConnect)
End Try

End Sub

   ・
   ・

End Class


●Module
Imports System.Data
Imports System.Data.SqlClient

Module Module1

Function funDBOpen(ByRef DBConnect As SqlConnection) As Boolean

Dim strCnn As String
funDBOpen = False

Try
'接続文字列をWeb.configから取得
strCnn = ConfigurationSettings.AppSettings("DBConnectionString")

'DB接続
DBConnect.ConnectionString = strCnn
DBConnect.Open()

funDBOpen = True
Catch
'エラー処理
End Try

End Function


Function funRecOpen(ByVal strSql As String, ByRef DBReader As SqlDataReader, _
ByRef DBConnect As SqlConnection) As Boolean

funRecOpen = False

'コマンドオブジェクト作成
Dim DbCommand As New SqlCommand()

Try
If (DBConnect Is Nothing) Or (strSql = "") Then
DBReader.Close()
DBReader = Nothing
Exit Function
End If

DbCommand.Connection = DBConnect
DbCommand.CommandText = strSql
DBReader = DbCommand.ExecuteReader()

funRecOpen = True
Catch
'エラー処理
Finally
DbCommand = Nothing
End Try

End Function

Sub subRecClose(ByRef DBReader As SqlDataReader)
Try
If Not DBReader Is Nothing Then
DBReader.Close()
DBReader = Nothing
End If
Catch
'エラー処理
End Try

End Sub

Sub subDBClose(ByRef DBConnect As SqlConnection)

Try
If Not DBConnect Is Nothing Then
'DB切断
DBConnect.Close()
DBConnect.Dispose()
DBConnect = Nothing
End If

Catch
'エラー処理
End Try

End Sub



Function funGetInfo(ByRef DBConnect As SqlConnection) As Boolean

Dim DBreader As SqlDataReader
Dim strSQL As String

funGetInfo = False

Try
strSQL = "SELECT * FROM <テーブル名>"
strSQL &= " WHERE <ユーザID> = " & HttpContext.Current.Session("<ユーザID>").ToString
strSQL &= " AND <営業所ID> = " & HttpContext.Current.Session("<営業所ID>").ToString

If funRecOpen(strSQL, DBreader, DBConnect) = False Then
Exit Function
End If

If DBreader.Read() = True Then

   ・
   ・

End If

funGetInfo = True

Catch
'エラー処理
Finally
Call subRecClose(DBreader)
End Try

End Function
End Module


●現象発生の操作
ログイン後、しばらくは本人のユーザ名・営業所名が表示される。
しばらく動かした後、上記のメニュー画面に戻った際に、他人の
ユーザ名・営業所名が表示される。



以上を踏まえて、再度私の疑問点を挙げさせて頂くと、
「メニュー画面の情報取得部分が静的変数によって他人の結果が
 返ってきたとしても、その直後に
  txtTanto.Text = Session("<ユーザ名>").ToString
 としている部分で他人のユーザ名が表示されるのはなぜでしょうか?」
という事です。

自分なりに考えてみると、
・メニュー画面に戻ってくる前に、何かしらの理由によって
 「Session("<ユーザ名>")」が他人のものに上書きされていた。
かと思うのですが、この「Session("<ユーザ名>")」を使用するのは
上記メニュー画面を含めて2箇所、かつ使い方は同じでテキストボックスに
セットしているだけのため、上書きされる理由が分からないのです。
(「Session("<ユーザ名>")」に値をセットするのはログイン画面の1箇所。)


(余談)
最初の書込みでは情報が少なすぎて、皆さんの考えるモトがなかったのですね。
おおいに反省しております。

todo
ぬし
会議室デビュー日: 2003/07/23
投稿数: 682
投稿日時: 2005-09-11 22:25
IEで CTRL+N を押すと、別のIEが起動します。
一方でAでログインし、もう一方でBでログインすれば現象が出ると思います。
これは、二つのIEがセッションを共有してしまうからです。

しかし、別のパソコンならセッションを共有するのは有り得ないはずです。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2005-09-12 21:21
引用:

最初の書込みでは情報が少なすぎて、皆さんの考えるモトがなかったのですね。
おおいに反省しております。


 ん〜、応える人の多くは考えることが楽しいんだから、考えるネタがたくさんあるのは、それはそれでおもしろいんですよ。
 ただ、後出しジャンケンをされると嫌な気がするし、それが文字にでちゃうとあなたも嫌な思いをするし、問題解決もズルズル後ろへ行っちゃう。それだけのことです。
_________________

スキルアップ/キャリアアップ(JOB@IT)