none
ASP.net + C#.net にて、@OutputCache の設定を動的に変更したい。 RRS feed

  • 質問

  • みなさん、こんにちわ。

    ASP.net と C#.netでの、キャッシュについて、質問があります。

    現在、Form_Loadイベントを必ず発生させるために、@OutputCacheディテクティブにてキャッシュ無効化しています
    (<%@ OutputCache Location="None" VaryByParam="None" %>)。

    ですが、同じASPの画面で、ASPボタンタグからのイベントで、動的にテキストファイルを生成してダウンロードさせる処理を実装した所、IE6でのみ「開く」が出ませんでした。
    具体的には、メモ帳で「ファイルが見つかりません」というエラーが発生します。
    なお、「保存」を行うと、問題なく保存できる事は確認しました。
    また、@OutputCacheディテクティブを削除して、キャッシュを有効にすると、問題なく開く事も確認しております。

    ですが、@OutputCacheディテクティブを外すと、Form_Loadイベントを必ず発生させるという問題が対処出来なくなる為に外す事が出来ず、別の手段を探しております。

    @OutputCacheディテクティブの設定をそのままにして、IE6で「開く」を問題なく行うにはどうすれば宜しいでしょうか?

    以上、よろしくお願いします。

    ---------------------------------------------------------------------------------
    環境
     開発:VS2008
     ソリューション:Webアプリケーション
     言語:C#、ASP.net
     クライアントOS:XP Pro
     ブラウザ:IE6 SP3

    動的DL用コード

    Response.CacheControl = "public";
    Response.AddHeader("Pragma", "public");
    Response.Cache.SetCacheability(HttpCacheability.Public);
    Response.Cache.SetExpires(DateTime.Now.AddMinutes(1));
    Response.Cache.SetValidUntilExpires(true);
    Response.Cache.VaryByHeaders["Accept-Language"] = true;
    
    Response.HeaderEncoding = System.Text.Encoding.GetEncoding("shift_jis");
    //Response.ContentType = "application/octet-stream";
    //Response.ContentType = "text/plain";
    Response.ContentType = "text/download";
    Response.AddHeader("content-disposition", "attachment; filename=メッセージ.txt");
    Encoding encodeObj = Encoding.GetEncoding("shift_jis");
    StringBuilder sb = new StringBuilder();
    sb.AppendLine("タイトル");
    sb.AppendLine();
    sb.AppendLine("メッセージ");
    byte[] bytes = encodeObj.GetBytes(sb.ToString());
    Response.BinaryWrite(bytes);
    Response.End();

    ※追記
    2012/05/15
    上記質問文にて、不足している情報、および間違ったコードがありましたので、訂正いたします。

    【追記情報】
    環境
     .net framework 3.5

    動的DL用コード

    動的DL用コード(ボタンクリックイベントにて実行される。~.aspx.csファイルに記述)

    【コード修正】
    元のコード

    Response.ContentType = "text/download";
    Response.AddHeader("content-disposition", "attachment; filename=メッセージ.txt");
    
    正しいコード
    1行目~6行目まで削除。
    かつ、上記コードを以下のコードと置き換え。
    Response.ContentType = "application/octet-stream";
    Response.AddHeader("content-disposition", "attachment; filename=message.txt");


    以上、ご迷惑をお掛けいたしました。

    • 編集済み うぃずあすら 2012年5月15日 4:05 情報の不足、およびコード記述ミス
    2012年4月24日 8:30

すべての返信

  • コードの詳細まで読んでないのでハズレかもしれませんが、以下
    の問題ではないですか?

    Content-Disposition: attachemnt と Cache-Control: no-cache
    によるダウンロードの問題
    http://support.microsoft.com/default.aspx?scid=kb;ja;436605


    どうも見当はずれなことをされているような気がします(違ってい
    たら失礼しました)。

    なぜ「Form_Loadイベントを必ず発生」させたいのか、そのバック
    グラウンド、理由などを書いたほうがいいと思います。

    もし、質問が的外れだとすると、回答も的外れになって、いつまで
    経っても本当の問題は解決できないことになりがちです。

    実際に何がやりたいことか分かれば、それは見当ハズレだから、こ
    うしてはどうかというようなアドバイスができるかもしれません。

    2012年4月24日 13:29
  • SurferOnWwwさん。
    早速のご回答、ありがとうございます。

    現象としては、上げて頂いたサポートの件(Content-Disposition: attachemnt と Cache-Control: no-cache によるダウンロードの問題)そのものです。

    「Form_Load」イベントが必須である理由ですが、実装中のページは別ページで変更された内容を元に、初期表示時に表示を「Form_Load」イベントで変えている為、「Form_Load」イベントが必須となっています。

    開発環境では、IE8で確認していた為、単体テストでは問題なく動作しておりました。
    その後、Windowsサーバにデプロイして、XP&IE6環境にて結合テストを行った所、上げて頂いたサポートの件に引っかかり、問題となっております。

    実現したい事は、以下の内容です。
    ・ページは初期表示と、ページ中の操作で、動的に変更される(この実現の為に、キャッシュを無効にしています)。
    ・同じページ内にあるダウンロードボタンをクリックして、サーバ側でテキストファイルを生成し、ダウンロードを行います。
    ・ダウンロードされるテキストファイルは、ダイアログから「開く」「保存」が行われます(どちらか一方ではありません)。
    ・セキュリティ上、ポップアップブロックが掛かっています。

    以上、アドバイスをよろしくお願いいたします。
    2012年4月25日 10:54
  • 依然として状況が理解できませんのでハズレかもしれませんが・・・

    あるページで <%@ OutputCache Location="None" VaryByParam="None" %>
    と設定すると、応答 HTTP ヘッダでは以下のように設定されるはずです。

    Cache-Control: no-cache
    Expires: -1
    Pragma: no-cache

    この意味は分かるでしょうか? それらはクライアントマシン上のブラウ
    ザ、もしくはクライアントマシンと Web サーバの間に位置する Proxy サ
    ーバに対してキャッシュしないように指示するためのものです。

    一方、<%@ OutputCache ... を設定しないと以下のようになるはずです。

    Cache-Control: private

    この場合、クライアントマシン上のブラウザのキャッシュから取得する場
    合があるということを問題にされているのだと思いますが・・・


    > 同じページ内にあるダウンロードボタンをクリックして、サーバ側
    > でテキストファイルを生成し、ダウンロードを行います。

    この時、[ダウンロードボタン]をクリックするとポストバックがかかる
    のですよね。

    そうであれば、ブラウザは必ずそのページを要求 (POST) し、要求を受け
    たサーバー側ではそのページがロードされて Page.Load イベントが発生す
    るはずです。(キャッシュからは取得しない)

    つまり、<%@ OutputCache Location="None" VaryByParam="None" %> はあ
    ってもなくても Page.Load イベントが発生するはずなのですが。

    2012年4月25日 13:48
  • SurferOnWwwさん。
    たびたびのご回答、ありがとうございます。

    キャッシュに関するHTTPヘッダの内容については、認識できております。
    そして、Page_Load イベントの発生に関しても、問題ありません。

    問題があるのは、ポストバックにて発生したボタンクリック時イベントメソッドで、Response.Write実行後に起こるIE6側の挙動です(つまり、サーバ側レスポンス完了後のクライアント動作)。
    IE6側でダウンロード時の確認ダイアログは開きますが、ダイアログで「開く」を実行すると、メモ帳で「ファイルがない」と言われる点が問題なのです。
    最初の投稿でも書いたとおり、「保存」に関しては問題ありませんし、IE8でも問題なく動作しております。

    最初の投稿で書いた、
    > @OutputCacheディテクティブの設定をそのままにして、IE6で「開く」を問題なく行うにはどうすれば宜しいでしょうか?
    という点が一番重要です。

    なお、Page_Load イベントが“必ず”発生してくれるなら、
    @OutputCacheディテクティブの設定にはこだわりません(私の知識では、@OutputCacheディテクティブのLocation="None"以外の方法が分からない為、「設定をそのままに」と書きました)。

    暫定的な対応として、@OutputCacheディテクティブの設定で、キャッシュ保存時間を1秒にして、IE6で「開く」が問題なく動作する事を確認しました。
    ですが、@OutputCacheディテクティブ本来の意味としては、「キャッシュしない=Location="None"」が正しいと思うので、「Location="None"」を設定した上で、IE6で「開く」が問題なく動作する方法があれば、教えて欲しいと思います。

    以上、よろしくお願いいたします。

    2012年4月26日 3:18
  • 要件は以下の 2 つでしょうか。まずこれを確認ください。

    (1) ボタンクリックでポストバックしたとき、必ずページがサーバー
      のメモリにロードされ Page.Load イベントが発生する(サーバ
      ーのページ出力キャッシュから取得しない)。

    (2) ダウンロードされたテキストファイルを直接開くことができるよ
      うにする(現在のところ、Content-Disposition: attachemnt と
      Cache-Control: no-cache の問題で開けない)


    上記の理解が正しいとして・・・

    > 最初の投稿で書いた、
    > @OutputCacheディテクティブの設定をそのままにして、IE6で
    >「開く」を問題なく行うにはどうすれば宜しいでしょうか?
    > という点が一番重要です。
     
    それでは、Content-Disposition: attachemnt とCache-Control:
    no-cache の問題が解決できない(即ち IE6 で開けない)のでは? 
    であれば、「@OutputCacheディテクティブの設定をそのまま」には
    できないのではないですか?

    先のレスで <%@ OutputCache Location="None" VaryByParam="None" %>
    はなくても、ボタンクリックでポストバックしたら Page.Load イベント
    は発生するとレスしましたが、そこは確認されたでしょうか?

    <%@ OutputCache Location="None" VaryByParam="None" %> があっても
    なくても、Page.Load イベントは必ず発生するはずです。まずはそこを
    デバッガで追いかけるなどして確認してください。

    一方、<%@ OutputCache Location="None" VaryByParam="None" %> がある
    から Cache-Control: no-cache の問題でダウンロードしたテキストファ
    イルが IE で開けないのですよね?

    であれば、<%@ OutputCache Location="None" VaryByParam="None" %> を
    削除すれば開ける(上記 (2) の要件は満足する)はずですし、上記 (1)
    の要件も満足すると思えますが、違いますか?


    > ですが、@OutputCacheディテクティブ本来の意味としては、「キャッ
    > シュしない=Location="None"」が正しいと思うので

    そこのところ誤解されているのでは? キャッシュする場所としては以下
    のように 3 ヶ所あります。どこのことを言っていますか?

    (1) クライアントマシン上のブラウザ

    (2) クライアントマシンと Web サーバの間に位置する Proxy サーバ

    (3) Web サーバ

    2012年4月26日 13:01
  • > それでは、Content-Disposition: attachemnt とCache-Control:
    > no-cache の問題が解決できない(即ち IE6 で開けない)のでは?
    > であれば、「@OutputCacheディテクティブの設定をそのまま」には
    > できないのではないですか?
    そうですね。
    ですが、すぐ下の文で「Page_Load イベントが“必ず”発生してくれるなら、設定にこだわらない」とも書いてあります。
    ですから、@OutputCacheディテクティブが原因ではありますが、それは今回の問題の本質ではありません。
    @OutputCacheディテクティブの「Location="None"」と全く同じようにPage_Load イベントが必ず呼ばれる設定をページで行えて、かつIE6の問題を回避できる方法があれば、教えて欲しいのです。


    > 先のレスで <%@ OutputCache Location="None" VaryByParam="None" %>
    > はなくても、ボタンクリックでポストバックしたら Page.Load イベント
    > は発生するとレスしましたが、そこは確認されたでしょうか?
    イベント実行が確認できていなければ、別の不具合を調査しています。
    そして、イベント実行が出来ない場合があった為、キャッシュ無効化の設定をしております。
    なお、サーバ側の処理に問題が無い事は、イベントメソッドや分岐ごとにログ出力させて確認済みです。
    また、今回はサーバ側処理自体は問題にしておりません(少なくとも「保存」が実行できる時点で、サーバのResponse処理は正しく動作しています)。


    > 一方、<%@ OutputCache Location="None" VaryByParam="None" %> がある
    > から Cache-Control: no-cache の問題でダウンロードしたテキストファ
    > イルが IE で開けないのですよね?
    より正確に言えば、「ダウンロード時に開くダイアログから、ダウンロード対象の動的生成テキストファイルを直接開けない」です。
    「保存」は正しく動作しており、内容も正しい事を確認しています。
    つまり、IE6の挙動自体が問題であり、IE6を使って、IE6が持っている問題の回避方法を探していると書いております。
    なお、今回のシステムでは、エンドユーザー側の意向でIE6の利用は絶対です。
    また、パッチなどのインストールも不可です。
    さらに各クライアントの設定変更も禁止されております。


    > であれば、<%@ OutputCache Location="None" VaryByParam="None" %> を
    > 削除すれば開ける(上記 (2) の要件は満足する)はずですし、上記 (1)
    > の要件も満足すると思えますが、違いますか?
    一番最初の投稿内容をきちんと読んで欲しいです。
    『また、@OutputCacheディテクティブを削除して、キャッシュを有効にすると、問題なく開く事も確認しております。』
    と書いており、その方法はすでに一度試しております。
    その上で、キャッシュを無効化したまま(正確には“確実に”Page_Loadイベントが実行される状態で)、IE6でダウンロードダイアログの「開く」が正しく動作する方法が知りたいのです。
    キャッシュを無効化している理由もきちんと書いてありますが、読まれておりますでしょうか?
    さらに言えば、IE8では全く問題なく開く事が出来ております(ブラウザを変えただけで問題が解決する=サーバ側の問題ではない)。


    > > ですが、@OutputCacheディテクティブ本来の意味としては、「キャッシュしない=Location="None"」が正しいと思うので
    > そこのところ誤解されているのでは?
    どのような誤解でしょうか?
    常に最新の状態を出力させる為に、キャッシュさせたくないのですから、ブラウザやサーバ内、または中間プロクシサーバにキャッシュを持たれては困ります。
    そういう意味では「Location="None"」を設定する必要があると考えておりますが、いかがでしょうか?



    質問に対して真摯に答えていただけるのは、大変嬉しいのですが、
    どうも質問を理解しないまま、個々の記述だけで回答されている感じがします。
    なお、現象としては、以下のURL(別サイトですが)の質問と全く同じです。
    ASP.NETアプリからのTXTファイルのダウンロード障害
    上記URLの質問では、明確な回答がなかった(原因の特定だけで完了している)ため、より詳しい回避策を求めて質問した次第です。

    以上、誠にお手数かと思いますが、何とぞよろしくお願いいたします。


    2012年4月26日 13:57
  • 一番答えてほしいところに答えていただいてないので、もう一度書き
    ます。

    要件は以下の 2 つでしょうか。まずこれを確認ください。
     
    (1) ボタンクリックでポストバックしたとき、必ずページがサーバー
       のメモリにロードされ Page.Load イベントが発生する(サーバ
       ーのページ出力キャッシュから取得しない)。
     
    (2) ダウンロードされたテキストファイルを直接開くことができるよ
       うにする(現在のところ、Content-Disposition: attachemnt と
       Cache-Control: no-cache の問題で開けない)

    2012年4月26日 16:59
  • SurferOnWwwさん。
    たびたびのご回答、ありがとうございます。


    > (1) ボタンクリックでポストバックしたとき、必ずページがサーバー
    >    のメモリにロードされ Page.Load イベントが発生する(サーバ
    >    ーのページ出力キャッシュから取得しない)。
    ポストバックだけでなく、サーバアクセス時に必ず実行する事が必要ですが、概ねその通りでございます。

    最初の投稿にて
    > 現在、Form_Loadイベントを必ず発生させるために、@OutputCacheディテクティブにてキャッシュ無効化しています
    と書いてある通りです。


    > (2) ダウンロードされたテキストファイルを直接開くことができるよ
    >    うにする(現在のところ、Content-Disposition: attachemnt と
    >    Cache-Control: no-cache の問題で開けない)
    その通りでございます。

    2つ目の投稿にて
    > 現象としては、上げて頂いたサポートの件(Content-Disposition: attachemnt と Cache-Control: no-cache によるダウンロードの問題)そのものです。
    と書いてある通りです。


    以上、アドバイスよろしくお願いいたします。
    2012年4月27日 4:18
  • > ポストバックだけでなく、サーバアクセス時に必ず実行する事が必要です

    「サーバアクセス」とはどういう意味ですか?

    ブラウザがサーバーに要求を出すという意味なら、@ OutputCache
    ディレクティブを設定しない(結果は Cache-Control: private になるはず)
    が (1), (2) 両方の要件の解決策になるはずです。

    デフォルトでは、.aspx ページはブラウザキャッシュからもプロキシキャッ
    シュからも提供されません。@ OutputCache ディレクティブを設定しないの
    だから、サーバーにもキャッシュされていません。なので、必ず Page.Load
    イベントは発生するはずです。

    実際に、要求が出ないとか、出てているのに Page.Load イベントが発生しない
    という問題があるなら具体的にどういうケースか書いてください。


    上記のようなことではなくて、ブラウザの[戻る]ボタンをクリックするこ
    とまで含めて、ユーザーの操作すべてを「サーバアクセス」と言っています
    か? それなら、Cache-Control: private ではブラウザのキャッシュから
    取ってくるケースがあるので「必ず実行」できないのは分るのですが。



    • 編集済み SurferOnWww 2012年4月27日 13:38 誤記訂正
    2012年4月27日 13:23
  • 返信が遅くなりまして、申し訳ありませんでした。
    何度もご回答下さいまして、ありがとうございます。


    「サーバアクセス」に関する逆質問ですが、少し言葉が足らなかったようですね。
    ASPアプリケーション“サーバ”に“アクセス”(通信)するという事です。
    「戻る」機能はツールバーをJavascriptで非表示にしていますが、履歴を戻った場合でも同様です(システム上エラー表示するようにしています)。


    > デフォルトでは、.aspx ページはブラウザキャッシュからもプロキシキャッ
    > シュからも提供されません。@ OutputCache ディレクティブを設定しないの
    > だから、サーバーにもキャッシュされていません。なので、必ず Page.Load 
    > イベントは発生するはずです。
    デフォルト設定の場合、二度目以降のアクセス時の保証はされておりません(「Cache-Control: private」という事は、ブラウザ側でのキャッシュは許可すると言う事です)。
    どこで「イベントは発生するはず」という判断をされたのか不明ですが、ブラウザ側がキャッシュ利用すると判断した場合、ブラウザが保持しているキャッシュデータを表示する為、サーバアクセスは発生しません(逆にサーバアクセスしてしまったら、キャッシュの意味がない)。
    ただし、私もHTTPのプロトコルに関する振る舞いを完全に理解出来ているとは言えない為、サーバ側の情報取得の為のアクセスを完全に行っていないとは言い切れませんけれど、ASPアプリケーション“サーバ”へのアクセスを行わない場合は確実に存在します。


    > 実際に、要求が出ないとか、出てているのに Page.Load イベントが発生しない
    > という問題があるなら具体的にどういうケースか書いてください。
    キャッシュ設定がデフォルト状態の時にForm_Loadイベントが発生しない事がある事象は、LAN環境では殆ど発生しません(私の開発環境では再現しませんでした)。

    私が確認したのは、私のいる開発拠点とは別の県にある会社に協力をしてもらって結合テストを行った時に、ルータ越しにポート開放したネットワークでForm_Loadイベントが発生しない事象が発生しました(10回に1回程度です)。

    なお、このような事象は、他の方でも発生している事を確認しております。
    2回目のPage_Loadが処理されない」や「みみちゃんblog - プログラムの園」などに書かれております。




    ところで、論点がずれているような気がします。
    Form_Loadイベントに関する事ばかり確認されていますが、ファイル動的出力処理は最初の投稿に「ASPボタンタグからのイベントで」と明記しております。
    Form_Loadイベントのみクローズアップされても、ASPページ上必須であるという以上の理由はなく、「ASPボタンタグからのイベント」が実行される事の方が重要だと認識しております。

    また、IE8で問題なく実行出来ている(IE8で実行出来ている点については、1つ目の返信にて記載)と言う事は、ブラウザ側のキャッシュの扱いに関する問題と言う事です。




    とりあえずの暫定対処で、OutputCache ディレクティブの Duration 属性に1を設定する事(キャッシュ有効期限1秒)で、殆どの場合でForm_Loadイベントを実行させるように対応いたしました。
    1秒未満のアクセス時に問題が発生する可能性が捨てきれませんが、暫定の為にやむなくの処置ですね。
    上記の方法以外で、より有効な手段があれば、どなたか御教示して頂けると幸いです。

    2012年5月7日 8:30
  • > ASPアプリケーション“サーバ”に“アクセス”(通信)するという事です。

    どういう意味ですか? 用語の意味を正しく理解して使っていますか? 

    単に Web サーバーにアクセスというなら、ブラウザからでなくとも可能で
    すよ。そようなことを議論しているわけではないですよね。そんなことを言
    っていると、話が一向に収束しません。

    具体的に言うと、IIS に IE6 が GET または POST 要求を出すケースに限定
    した話ではないのですか。

    > 「戻る」機能はツールバーをJavascriptで非表示にしていますが、履歴を
    > 戻った場合でも同様です(システム上エラー表示するようにしています)。
     
    具体的にどうしたのかは知りませんが、何にせよ、IE6 の[戻る][進む]
    ボタンをクリックするのは「アクセス」の範囲外なのですよね。

    違いますか? もし違うなら、正しい用語で具体的にケースを特定して書い
    てください。でないと掲示板では話が通じません。

    > デフォルト設定の場合、二度目以降のアクセス時の保証はされておりませ
    > ん(「Cache-Control: private」という事は、ブラウザ側でのキャッシュ
    > は許可すると言う事です)。

    そんなことはありません。max-age も Expires も指定されてないのだから、
    キャッシュは常に古いと見なされます。そのため、ASPX リソースをリクエス
    トすると、ページがキャッシュされてない場合と同じように、常にサーバーか
    ら新しいリソースを取得することになります。

    信用できませんか? 以下のページや「プログラミング ASP.NET 4」の第 18
    章(特に 18.3 項あたり)を読んでみて下さい。

    Cache-control private?
    http://forums.asp.net/t/1443346.aspx/1

    > どこで「イベントは発生するはず」という判断をされたのか不明ですが、ブ
    > ラウザ側がキャッシュ利用すると判断した場合、ブラウザが保持しているキ
    > ャッシュデータを表示する為、サーバアクセスは発生しません(逆にサーバア
    > クセスしてしまったら、キャッシュの意味がない)。

    Cache-Control: private はブラウザのみでキャッシュするという意味だという
    ことは理解できているでしょうか? それが理解できていれば、ブラウザが要
    求を出せば、その先ではどこもキャッシュされているところはないので、要求
    はサーバーまで届いて、そこで処理されることは理解できますか?

    その場合、サーバーのメモリにページがロードされて Page.Load イベントは
    必ず発生します。

    ただし、特殊な環境で、例えば、要求がどこかで消えてなくなってしまうとい
    うようなことは考えていませんよ。そればまた別な話です。

    > ただし、私もHTTPのプロトコルに関する振る舞いを完全に理解出来ていると
    > は言えない為、、サーバ側の情報取得の為のアクセスを完全に行っていない
    > とは言い切れませんけれど、

    その通りで、掲示板ではなかなか話が通じていないのが今の状況だと思います。
    もう少し勉強されることをお勧めします。

    > ASPアプリケーション“サーバ”へのアクセスを行わない場合は確実に存在し
    > ます。

    そういうケースがあるのは確かですけど、Cache-Control: private の場合は
    ブラウザの[戻る][進む]ボタンをクリックした場合ぐらいです。

    > キャッシュ設定がデフォルト状態の時にForm_Loadイベントが発生しない事
    > がある事象は、LAN環境では殆ど発生しません(私の開発環境では再現しませ
    > んでした)。

    Form_Load ではなくて Page.Load イベントでしょ。とにかく、あなたの「LAN
    環境」では、かならずブラウザから要求が出て、サーバーでは Page.Load イベ
    ントが発生したのですよね。

    > 私が確認したのは、私のいる開発拠点とは別の県にある会社に協力をしても
    > らって結合テストを行った時に、ルータ越しにポート開放したネットワークで
    > Form_Loadイベントが発生しない事象が発生しました(10回に1回程度です)。

    Form_Load ではなくて Page.Load イベントです。

    何にせよ、何が原因なのか、そもそも本当に Page.Load イベントが発生しなか
    ったのか分からないのでは? ここを見ている閲覧者が誰でも納得できるよう
    に書けますか?
     
    > なお、このような事象は、他の方でも発生している事を確認しております。
    > 「2回目のPage_Loadが処理されない」や「みみちゃんblog - プログラムの園」
    > などに書かれております。

    その中身を理解してますか。ざっと読んでみましたが、前者は[戻る]ボタンク
    リック、後者は問題があった時の設定が不明です。このようなページは、今回の
    話には何の意味もありません。

    > ところで、論点がずれているような気がします。

    このような発言は失礼です。あなたの理解力、問題を説明するのに必要なスキル
    に問題はないと言えますか?

    > Form_Loadイベントに関する事ばかり確認されていますが、ファイル動的出力処
    > 理は最初の投稿に「ASPボタンタグからのイベントで」と明記しております。
     
    Form_Load ではなくて Page.Load イベントです。

    分かっていないようですが、Page.Load イベントが発生するということは、どこ
    でもキャッシュから応答が返されず、サーバーまで要求が届いて、サーバーでペ
    ージがロードされ処置されているということです。

    ボタンクリックでポストバックしたのなら、その後必ず Button.Click イベント
    は発生します。だから、まず Page.Load イベントが発生するかを議論している
    のです。わかりますか?

    > また、IE8で問題なく実行出来ている(IE8で実行出来ている点については、1
    > つ目の返信にて記載)と言う事は、ブラウザ側のキャッシュの扱いに関する問
    > 題と言う事です。

    その通り IE6 の問題です。でも、IE6 を使うというのが要件なのだから、どう
    しようもないですよね。

    > とりあえずの暫定対処で、OutputCache ディレクティブの Duration 属性に1
    > を設定する事(キャッシュ有効期限1秒)で、殆どの場合でForm_Loadイベント
    > を実行させるように対応いたしました。

    それははっきり言ってメチャクチャです。理解してやっているとはとても思え
    ません。

    > 上記の方法以外で、より有効な手段があれば、どなたか御教示して頂けると
    > 幸いです。

    どうしても <%@ OutputCache Location="None" VaryByParam="None" %> とした
    いなら、ダウンロードするのを別ページで行ってはどうですか。

    2012年5月7日 14:31
  • SurferOnWwwさん。
    早速の回答ありがとうございます。



    > Form_Load ではなくて Page.Load イベントです。
    これは恥ずかしい書き間違いをしていました。申し訳ないです。
    Form_Load」ではなく、「Page_Load」イベントメソッドの書き間違いですね
    (納品しているアプリや、検証用アプリでは「Page_Load」で実装している事を確認しましたので、お粗末なミスですね。重ね重ね、申し訳ありません)。



    > そんなことはありません。max-age も Expires も指定されてないのだから、
    > キャッシュは常に古いと見なされます。そのため、ASPX リソースをリクエス
    > トすると、ページがキャッシュされてない場合と同じように、常にサーバーか
    > ら新しいリソースを取得することになります。
    えっと、Cache-Control のデフォルトは private ですよね?
    私の勘違いでなければ、HTTPヘッダの Cache-Control は Expires よりも
    優先されると記憶しておりますが、間違いでしょうか?

    [Studying HTTP] HTTP Header Fields

    HTTP 状態管理メカニズム



    > > また、IE8で問題なく実行出来ている(IE8で実行出来ている点については、1
    > > つ目の返信にて記載)と言う事は、ブラウザ側のキャッシュの扱いに関する問
    > > 題と言う事です。
    > その通り IE6 の問題です。でも、IE6 を使うというのが要件なのだから、どう
    > しようもないですよね。
    その通りですが、その点は別にご指摘頂かなくても十分に理解しておりますので、あえて書かれなくても結構です。



    > ボタンクリックでポストバックしたのなら、その後必ず Button.Click イベント
    > は発生します。だから、まず Page.Load イベントが発生するかを議論している
    > のです。わかりますか?
    “動的生成した”テキストファイルがダウンロードできる時点で、イベントが発生している事は至極当然の事と認識しておりました。
    動的生成はASPアプリケーションが行うもので、提示したコードではResponseクラスで直接出力しておりますから、「イベントが発生しない=ダウンロード自体が発生しない」という事を、当然と考えておりました。
    それより前の話だとは全く思いもせず、申し訳ありませんでした。



    > > とりあえずの暫定対処で、OutputCache ディレクティブの Duration 属性に1
    > > を設定する事(キャッシュ有効期限1秒)で、殆どの場合でForm_Loadイベント
    > > を実行させるように対応いたしました。
    > それははっきり言ってメチャクチャです。理解してやっているとはとても思え
    > ません。
    承知の上で実装しています。
    暫定対処と書いてある点を読んで頂きたいと思いますが、難しいのでしょうね。

    納期期限と調査や実装の時間の兼ね合いを考えると、実際の意味と違う実装であろうが、
    得られる結果が同じであれば実装せざるを得ない場合もありますので。

    なお、納得して実装しているわけではありません。
    その点は誤解なきよう。



    > > 上記の方法以外で、より有効な手段があれば、どなたか御教示して頂けると
    > > 幸いです。
    > どうしても <%@ OutputCache Location="None" VaryByParam="None" %> とした
    > いなら、ダウンロードするのを別ページで行ってはどうですか。
    試してみましたが、開く事は出来るようになりましたが、今度はポップアップ制限に引っかかりました。
    Responseクラスを使って動的にダウンロードさせようとした場合、ポップアップ(もしくは不正なダウンロード)として認識されてしまうようです。
    ブラウザ側の設定変更は認められていない為、この方法では無理と判断しました。

    また、ASPXページを一回表示させてからダウンロード処理を実行させると、どうしても一瞬ウィンドウが表示されてしまうので、やはり問題があると判断しました(別ページでExcelファイルのダウンロードが問題なく出来るので、同じ挙動を求められています。それがなければ、我慢してもらったのですが…)。

    検証の時間が足りなかったので、もしかするとポップアップ制限にも引っかからず、かつ別ウィンドウが表示される事もない状態で、別ページでダウンロード出来るのかもしれません。

    私としては、
    「IE6にて、キャッシュ無効時にテキストファイルダウンロード時の一時ファイルが作成されない」
    という問題が一番のネックではないかと考えているので ASP.net でこの問題が回避する方法が分かれば良いのですが…。


    • 編集済み うぃずあすら 2012年5月8日 6:23 一部の言葉を変更しました。
    2012年5月8日 6:21
  • > 私の勘違いでなければ、HTTPヘッダの よりもCache-Control は Expires
    > 優先されると記憶しておりますが、間違いでしょうか?

    Cache-Control と Expires のどちらが優先されるかという議論はしてませ
    ん。

    aspx ページのデフォルト、即ち Cache-Control: private のみで max-age
    も Expires も設定されてない状態でどうなるかを議論しています。

    先のレスをもう一度書きますが、「max-age も Expires も指定されてない
    のだから、キャッシュは常に古いと見なされます。そのため、ASPX リソー
    スをリクエストすると、ページがキャッシュされてない場合と同じように、
    常にサーバーから新しいリソースを取得することになります。」と言いま
    した。

    aspx ページのデフォルトで、毎回新しいリソースを取得することは、質問
    者さんの方でも、少なくとも「LAN 環境」では確認されたのでは?

    私のレスは信じない、紹介した Web ページや文書も信じない、おまけに
    ご自分で行った検証結果も信じないのですか?

    聞く耳持たないという感じですが、本当に解決する気があるんですか?


    > 暫定対処と書いてある点を読んで頂きたいと思いますが、難しいのでしょ
    > うね。

    暫定処置になどなりません。

    <%@ OutputCache Duration="1" VaryByParam="None" %> としたと思います
    が、その場合、ブラウザ、プロキシ、サーバーのすべてでキャッシュされ、
    応答ヘッダは以下のようになります。有効期間が 1 秒だから問題ないなん
    てことはなくて、複数のユーザーが同時アクセスすれば応答は間違いなく
    キャッシュから返されます。それでは要件を満たさないのでは?

    Cache-Control: public, max-age=1
    Date: Tue, 08 May 2012 12:29:19 GMT
    Expires: Tue, 08 May 2012 12:29:20 GMT

    一方、aspx ページのデフォルトでは以下のようになります。サーバー、プ
    ロキシではキャッシュされません。先に書きましたように、有効期限が示さ
    れてないので、ブラウザのキャッシュからも返されません([戻る][進む]
    ボタンをクリックしたような場合は除く)。

    Cache-Control: private
    Date: Tue, 08 May 2012 12:30:44 GMT

    それなのに、どういう理由で前者が暫定処置になり得るのですか。デフォ
    ルト(後者)が要件を満たすのに、わざわざ的外れな変更をするのが認め
    られることはありません。


    > 試してみましたが、開く事は出来るようになりましたが、今度はポップ
    > アップ制限に引っかかりました。

    別にダウンロード専用のページを作って、それにリダイレクトするように
    してはどうですか。それならポップアップブロックには引っかからないは
    ずです。

    例えば Button クリックでポストバックし、サーバー側で何か処置が必要
    なら Page.Load イベントのハンドラで処置し、ダウンロード専用ページに
    情報を渡す必要があれば Session またはクエリ文字列に情報を設定し、
    Button.Click イベントのハンドラでダウンロード専用ページにリダイレ
    クトするというような手段が考えられます。

    > 「IE6にて、キャッシュ無効時にテキストファイルダウンロード時の一時
    > ファイルが作成されない」という問題が一番のネックではないかと考え
    > ているので ASP.net でこの問題が回避する方法が分かれば良いのですが…。

    ASP.NET ができるのは、応答ヘッダの Cache-Control: no-cache の no-cache
    を private か public に変更することぐらいです。

    2012年5月8日 12:58
  • SurferOnWww さん。
    返信が非常に遅くなりました事をお詫びいたします。
    そして、回答ありがとうございます。


    結局の所、キャッシュの振る舞いの話と、イベントの話に終始した回答のような気がしますが、最後の方でやっと私の欲しい回答を頂いたような気がします。


    とりあえず「IE6にてキャッシュ無効状態の場合に動的生成したテキストファイルを開くと問題が発生する件について、有効な回避方法がないらしい」という事ですね。

    ダウンロード専用のASPファイルを作成してリダイレクトしてみましたが(通常のHTMLリダイレクト以外に、ASPのリダイレクトメソッドも別で試しました)、検証用コードに問題があったようで、やはりポップアップブロックに引っかかってしまいました。
    これ以上の検証は、リーダーに目を付けられるので検証続行出来ませんでした。
    専用ページの件については、せっかく提案して頂いたのに、検証して回答できず、申し訳ありません。

    この件については、全く解決はしておりませんが、上記にて書きました暫定対応(何度も言いますが納得してないですよ)にて対処という事で現場では納得してもらいました。
    本当なら、OutputCache ディレクティブのDuration属性に0が設定出来れば、ここまで不安にならずに済むのですが…(存続期間0というのも異常値なので、設定出来なくても仕方がないですね)。





    なお、以下は本当に蛇足です。
    教えて頂いたリンク先のフォーラムを読みました。
    確かに「which means that it won't be cached.」とあるので、ASPの理論上はデフォルトではキャッシュされないのでしょう。
    ASP.netの公式回答ではありませんけど。

    しかし
    > aspx ページのデフォルトで、毎回新しいリソースを取得することは、質問
    > 者さんの方でも、少なくとも「LAN 環境」では確認されたのでは?
    は勘違いをされております。
    私の文章の書き方が問題だろうとは思いますが、「LAN環境では」問題なく、「ルータ経由では」問題が発生したのです(プロキシサーバは間に入っていませんでした)。
    そして、他の返答で載せたリンク先の情報を元に解決致しました。

    ちなみに、RFC2616 の HTTP 1.1 に関する記述は読まれましたでしょうか?
    あいにく私は英語が苦手なので、原文ではなく翻訳したものを読みましたが、SurferOnWww さんが教えて下さったページの情報に書いてあるような「デフォルトではキャッシュされない」とは書かれておりません。

    ハイパーテキスト転送プロトコル -- HTTP/1.1(13.2.4 期限の計算)

    この場合、RFC の記述と私(および他の方)が実際に遭遇した現象か、それともASP.netのフォーラムの情報、どちらを信用するべきなんでしょうか。

    以上、長々とご回答、ありがとうございました。


    • 編集済み うぃずあすら 2012年5月15日 5:47 リンクのテキスト文章が、リンク先の内容の一部しか書いてなかった為、修正しました。
    2012年5月15日 5:37
  • > 結局の所、キャッシュの振る舞いの話と、イベントの話に終始した
    > 回答のような気がしますが、最後の方でやっと私の欲しい回答を頂
    > いたような気がします。

    正しい解は ASPX ページのデフォルト(@OutputCacheディテクティブ
    は指定しない)です。

    それは早い段階で回答していますが、いくら説明しても、うぃずあす
    らさんに理解していただけなかったので、結局「欲しい回答」になら
    なかったのだと思います。


    > ダウンロード専用のASPファイルを作成してリダイレクトしてみま
    > したが(通常のHTMLリダイレクト以外に、ASPのリダイレクトメソ
    > ッドも別で試しました)、検証用コードに問題があったようで、や
    > はりポップアップブロックに引っかかってしまいました。

    以下のようにすれば問題ないはずですが、どこが違うのでしょうか?

    <%@ Page Language="C#" %>
    <%@ OutputCache 
        Location="None" 
        VaryByParam="None" %> 
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            Label1.Text = DateTime.Now.ToString();
        }
    
        protected void Button1_Click(object sender, EventArgs e)
        {
            Response.Redirect("144-Download.aspx?datetime=" + 
                Server.UrlEncode(Label1.Text));
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head id="Head1" runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Button ID="Button1" 
                runat="server" 
                Text="Button" OnClick="Button1_Click" />
            <asp:Label ID="Label1" runat="server">
            </asp:Label>    
        </div>
        </form>
    </body>
    </html>

    ダウンロード専用ページ (144-Download.aspx)

    <%@ Page Language="C#" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <script runat="server">
    
        protected void Page_Load(object sender, EventArgs e)
        {
            string datetime = Request.QueryString["datetime"];
            
            Response.HeaderEncoding = 
                System.Text.Encoding.GetEncoding("shift_jis");
    
            Response.ContentType = "text/plain";
            Response.AddHeader("content-disposition", 
                "attachment; filename=test.txt");
            Encoding encodeObj = 
                Encoding.GetEncoding("shift_jis");
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("タイトル");
            sb.AppendLine();
            if (!String.IsNullOrEmpty(datetime))
            {
                sb.AppendLine("日時: " + datetime);
                sb.AppendLine();
            }
            sb.AppendLine("メッセージ");
            byte[] bytes = encodeObj.GetBytes(sb.ToString());
            Response.BinaryWrite(bytes);
            Response.End();
        }
    </script>
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>    
        </div>
        </form>
    </body>
    </html>

    > 本当なら、OutputCache ディレクティブのDuration属性に0が設定
    > 出来れば、ここまで不安にならずに済むのですが…(存続期間0と
    > いうのも異常値なので、設定出来なくても仕方がないですね)。

    @ OutputCache ディレクティブ以外でも、キャッシュ関係のヘッダの
    設定はできます。

    やろうと思えば、以下のようなコードで、

    Response.Cache.SetCacheability(HttpCacheability.Private);
    Response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
    Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));

    ヘッダを以下のように設定できます(結果的にはデフォルトと同じなの
    で、意味のある設定かは別にして)。

    Cache-Control: private, max-age=0
    Date: Tue, 15 May 2012 13:01:49 GMT
    Expires: Tue, 15 May 2012 13:01:49 GMT

    <%@ OutputCache Duration="1" VaryByParam="None" %> と
    するよりは説得力があるかも。


    > 教えて頂いたリンク先のフォーラムを読みました。
    > 確かに「which means that it won't be cached.」とあるので、ASP
    > の理論上はデフォルトではキャッシュされないのでしょう。

    「ASPの理論上」とは何ですか? そんなものは無くて、単純に IE6 の
    挙動の問題です。

    デフォルト (Cache-Control: private) で IE6 はキャッシュします。問
    題は IE6 がキャッシュから取得するかどうかです。

    後の方の記述 "With no Expires or max-age headers, the browser
    should request the page again if you come to it again. 
    However, browsers are free to do some "extra" caching when
    you're moving back-and-forth between a requested page in the
    same browser session." も読んでください。


    > ASP.netの公式回答ではありませんけど。

    紹介した本は「マイクロソフト公式解説書」です。そちらも読んでみ
    てください。


    > 「LAN環境では」問題なく、「ルータ経由では」問題が発生したの
    > です

    IE6 のキャッシュの問題なので、「LAN環境」では IE6 のキャッシュ
    から取得しなかったものが、同じデフォルト設定、同じ IE6 で「ル
    ータ経由」にすると 10 回に 1 回ぐらい IE6 のキャッシュから取得
    するなどということはあり得ません。「ルータ経由」の場合は別の問
    題でしょう。

    検証の際、Fiddler などのキャプチャツールを入れて、IE6 から要求
    が出ていたか否かを確認したのでしょうか? 要求が出てないが表示
    がされた(即ち、キャッシュから取ってきた)ことを確認できていな
    ければ、「問題が発生した」とは言えません。


    > ちなみに、RFC2616 の HTTP 1.1 に関する記述は読まれましたでし
    > ょうか? SurferOnWww さんが教えて下さったページの情報に書い
    > てあるような「デフォルトではキャッシュされない」とは書かれて
    > おりません。

    私はキャッシュされないとは一度も言っていません。紹介したページ
    も、上に書いたように、後の方の記述を読めばキャッシュされないとは
    言ってないことがわかります。

    デフォルト (Cache-Control: private) では IE6 にはキャッシュされ
    ます。なので、IE6 の[戻る]ボタンをクリックすれば、IE6 はキャッ
    シュから取得して表示します。

    3 回目ですけどもう一度書きます。「max-age も Expires も指定されて
    ないのだから、キャッシュは常に古いと見なされます。そのため、ASPX
    リソースをリクエストすると、ページがキャッシュされてない場合と同
    じように、常にサーバーから新しいリソースを取得することになりま
    す。」と言っています。


    > この場合、RFC の記述と私(および他の方)が実際に遭遇した現象か、
    > それともASP.netのフォーラムの情報、どちらを信用するべきなんで
    > しょうか。

    正しい解は ASPX ページのデフォルト(@OutputCacheディテクティブ
    は指定しない)と言っています。これだけ説明しても理解していただ
    けないなら、お手上げです。

    2012年5月15日 13:12
  • SurferOnWww さん。
    早速の返信、ありがとうございます。
    また、サンプルのソースコードも付けて頂き、ありがとうございます。

    Response.Cacheにてキャッシュ制御を行う方法は、@OutputCacheディレクティブを使用するよりもエレガント、というか本筋でしょうね。
    今からでも、そちらのコードに置き換えたいくらいですね(複雑な問題が絡んでいて、簡単にはコードいじれませんが…)。




    で、結局のところ、何度もキャッシュの話に戻ってしまっていますが、一部勘違いされている様子なので、少しだけ。

    まずは私の勘違いから。
    確かに「Cache-control private?」では「期限が切れた状態が設定される」と言うような内容が書かれていて、キャッシュはされていないとは言っていませんね(結果的にキャッシュとはならないという意味かな?)。
    その点について、私の書いた内容が間違ってました。

    ですが、デフォルト状態(@OutputCacheディレクティブ未設定)ではブラウザキャッシュを使用しない事が確約できないという事であれば、「ASPX ページのデフォルト(@OutputCacheディテクティブは指定しない)で問題ない」という回答では、Page_Loadイベントを必ず発生させるという条件がクリアできないと思うのですが、どうなのでしょう。

    「max-age も Expires も指定されてないのだから、キャッシュは常に古いと見なされます。そのため、ASPXリソースをリクエストすると、ページがキャッシュされてない場合と同じように、常にサーバーから新しいリソースを取得することになります。」
    と書かれておりますが、この情報は正しいのですか?
    私の“LANではない”環境では、Page_Loadイベントが発生していない場合がある事を確認していますし、同様の現象は他の方の環境でも発生している様子です(細かく上げる事はしませんが)。
    確認については、HTTPヘッダ確認用ツールではなく、もっと原始的に該当するASPページの全イベントメソッドにログ出力コードを実装して確認しました。



    ハッキリ言えば、一番最初の
    > コードの詳細まで読んでないのでハズレかもしれませんが、以下
    > の問題ではないですか?

    > Content-Disposition: attachemnt と Cache-Control: no-cache 
    > によるダウンロードの問題
    > http://support.microsoft.com/default.aspx?scid=kb;ja;436605
    が一番、的を射た確認です。
    それ以外のキャッシュに関する件に関しては、本筋から外れた確認と言えます(そもそも最初に「ダイアログから保存は問題なく出来ている」と書いたのでイベント発生に関する問題ではないと想定してくれると考えていたのですが、勝手に想定した私が甘かったと言えますね…。その点については申し訳ない事をしたと思っています)。



    これ以上は、質問の本筋とは完全に離れますので、これでキャッシュの話は終わりにしたいと思います。
    他の案を少し待ってから質問を完了としたいと思います。

    以上、ありがとうございました。
    2012年5月16日 10:32
  • > 「max-age も Expires も指定されてないのだから、キャッシュは
    > 常に古いと見なされます。そのため、ASPXリソースをリクエストす
    > ると、ページがキャッシュされてない場合と同じように、常にサー
    > バーから新しいリソースを取得することになります。」
    > と書かれておりますが、この情報は正しいのですか?

    正しいです。デフォルト以外の設定は、最初に言ったように、見当違
    いと言わざるを得ません。

    2012年5月16日 14:08