by WebSurfer
2013年6月29日 20:13
クラッシック ASP の場合は分かりませんが、ASP.NET の場合は、セッションの「タイムアウト」状態とフォーム認証の「ログアウト」状態は違います。
ASP.NET の場合「セッションタイムアウト」というと、MSDN ライブラリの セッション タイムアウトを構成する (IIS 7) によれば、sessionState 構成要素の timeout 属性に設定した時間が過ぎたことを言います。
セッションタイムアウトすると、サーバーに保存されていた SessionState 情報が破棄されます。しかし、それ以外の影響はありません。少なくともフォーム認証には無関係です。
また、SessionState 情報、SessionID、セッション Cookie のいずれからもフォーム認証のチケットに関する情報は取得できません。
なお、SessionState 情報を格納しない場合(Session["Data"] = xxxx; というようなコードが存在しない場合)、サーバーはセッション Cookie を発行しません。(2014/7/26 追記:Global.asax に Session_Start ハンドラを追加すると話が違ってきます。詳しくは、Session_Start ハンドラの影響 を参照ください)
SessionState 情報が格納される場合に限り、SeesionID を含むセッション Cookie が発行されます。なお、セッションタイムアウトしても SessionID は書き換えられず、同じ ID が使用され続けます。即ち、Session["Data"] に保存したデータは破棄されても、ブラウザは要求のたび同じセッション Cookie を送り続けます。
一方、フォーム認証の「ログアウト」状態とは認証チケットを持っていない、もしくは認証チケットは持っていても期限切れという状態です。セッションがタイムアウトしていても認証チケットは有効と言うことは当然あります。その逆もあります。
従って、フォーム認証チケットの有無もしくは期限切れと、セッションタイムアウトとは関係なく、セッションの「タイムアウト」状態 = フォーム認証の「ログアウト」状態にはならないです。
なお、Windows 認証、統合 Windows 認証は、フォーム認証とは全くメカニズムが異なっていて、セッションもクッキーも関係ないです。
by WebSurfer
2013年6月24日 14:55
このようなトラブルに悩む人はいないかもしれませんが、yield return ステートメント を使用した反復子のメソッドで using 句を使ったデータベースアクセスを行う場合の注意点を備忘録として書いておきます。
下のコードを見てください(SqlDataSource コントロールを利用すれば自力でこのようなコードを書く必要はありませんが、あくまで例として書きました)。
GetData が反復子のメソッドです。ここで注意しなければならないことは、このメソッドの戻り値(この例では IEnumerable<Employee> 型として定義されている employees)が foreach ループなどで反復処置されるまで GetData メソッドは呼び出されないことです。
従って、using のスコープの中で、まだ SqlDataReader が閉じられてないうちに、反復処置を完了しなければなりません。この例では、反復処置は GridView1.DataBind メソッドで行われますので、using のスコープの中で GridView1.DataBind メソッドを実行しなければなりません。
using のスコープを抜けた後で GridView1.DataBind メソッドを実行すると(下のコードでコメントアウトしたように)、その時点では SqlDataReader は閉じられているので、上の画像のように reader.Read() のところで "リーダーが閉じている場合は、Read の呼び出しは無効です。" というエラーが出ます。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
public class Employee
{
public string ID { get; set; }
public string Name { get; set; }
}
// yield return を使用した反復子のメソッド。戻り値が
// foreach ループなどで反復処置されるまで呼び出されない。
public IEnumerable<Employee> GetData(SqlDataReader reader)
{
while (reader.Read())
{
Employee employee = new Employee();
employee.ID = reader["EmployeeID"].ToString();
employee.Name = reader["LastName"].ToString();
yield return employee;
}
}
IEnumerable<Employee> employees = null;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string connString =
System.Web.Configuration.WebConfigurationManager.
ConnectionStrings["Northwind"].ConnectionString;
string query =
"SELECT EmployeeID, LastName FROM Employees";
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(query, conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
employees = GetData(reader);
// GetData メソッドが実行されるのは、employees が
// foreach などによって反復処置される時。ここで
// 以下のようにデータバインドすれば reader が開い
// ているうちに反復処置が完了するので問題なし。
GridView1.DataSource = employees;
GridView1.DataBind();
}
}
}
}
// ここでバインドしたのではダメ。GetData メソッドは
// using 句を抜けてから実行され、reader.Read() で
// "リーダーが閉じている場合は、Read の呼び出しは無
// 効です。" というエラーが出る。
//GridView1.DataSource = employees;
//GridView1.DataBind();
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
</div>
</form>
</body>
</html>
441d6c1b-fd5d-4c4a-8722-c0914c0288f1|1|5.0
Tags: yield
ADO.NET
by WebSurfer
2013年6月20日 13:15
先の記事「リソース埋め込みカスタムコントロール」で、画像、html ファイル、スクリプトファイル、css ファイルなどのリソースをアセンブリに埋め込んだカスタムコントロールの作り方を説明しました。
このようなリソース埋め込みカスタムコントロールを継承したコントロールを作って使う場合の注意点を書きます。
アセンブリに埋め込んだリソースは、GetWebResourceUrl メソッド によって URL 参照を取得して使用しますが、注意すべきはこのメソッドの第一引数 type(リソースの型)です。
先の記事の MsButton.cs のコードでは this.GetType() でリソースの型を取得していますが、このコントロールを継承した場合 this は継承先になり、ASP.NET は継承先からリソースを探すので、リソースが見つからないという結果になります。
この問題を解決するには this.GetType() に代えて typeof 演算子を利用します。先の記事の MsButton.cs のコードでは以下のようにします。
protected override void CreateChildControls()
{
ClientScriptManager cs = Page.ClientScript;
// このコントロールを継承する場合 this.GetType() ではダメ
// this は継承先になり、結果、リソースが見つからない。
//Type rsType = this.GetType();
Type rsType = typeof(MsButton);
// css への参照を <head></head> に配置
HtmlLink css = new HtmlLink();
css.Href =
cs.GetWebResourceUrl(rsType, "SimpleControl.MyStylesheet.css");
// ・・・中略・・・
}
上に紹介した MSDN ライブラリのサンプルコードでも typeof 演算子を使っていますね。