WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

customErrors と requestFiltering

by WebSurfer 2010年10月12日 12:17

先の記事 アプリケーションレベルの例外処理 で書きました、(1) Button 6 クリックおよび (2) 存在しない静的ファイルを要求した場合は、web.config の customErrors 要素にカスタムエラーページを設定してもそれが表示されない(下の画像のような標準エラーページが表示される)件につき理由を調べてみました。

標準エラーページ

調査結果をまとめると以下のとおりです(自信度 99% ぐらい。残り 1% の不安要素は後述します)。

(1) Button 6 クリック(Global-NoCatch.asax へリダイレクト)

IIS7 で導入された 要求のフィルタリング で、特定の拡張子(asa, asax, ascx など)のファイルに対する要求がブロックされています。

Global-NoCatch.asax へリダイレクトした場合は以下のようになります。拡張子でチェックしているので Global.asax でも結果は同じです。

要求フィルタモジュール (RequestFilteringModule) が拡張子 asax をチェックして拒否。 → 静的ファイルハンドラー (StaticFile) によって 404.7 エラーとして処理される。 → デフォルト(httpErrors 設定なし)では標準エラーページを返す。

先に applicationHost.config の設定を変えて(fileExtension=".asax" allowed="false" を true にして)試したときも、やはり標準エラーページになったのは、asax が静的ファイルハンドラー (StaticFile) によって処理されたためと思われます。

注意:
2014/4/19 時点の最新のサンプルでは、Button 6 クリックでのリダイレクト先が Global-NoCatch.asax から NonexistentPage-NoCatch.aspx/xxx...(xxx... は x が 500 文字)に変わっています。(遅くとも 2011/4/23 には変わっていたはず) 結果、HTTP/1.1 400 Bad Request が返ってきます。詳しくは下の「2011/4/23 追記」と「2011/8/22 追記」を見てください。

(2) 存在しない静的ファイルを要求

統合パイプラインモードでも既存のハンドラーマッピングはすべて機能したままなので、静的ファイルは依然として IIS のネイティブの静的ファイルハンドラー (StaticFile) によって処理される。 → デフォルト(httpErrors 設定なし)では標準エラーページを返す。

以上から、要求フィルタリングで拒否設定されているファイルや存在しない静的ファイルを要求されて、カスタムエラーページを返には、TechNet のページ HTTP エラー <httpErrors> の中の「カスタムエラーページを追加する方法」で述べられている手順を取るほかなさそうです。

なお、開発サーバーで検証すると動作が異なる件は、今後二度と開発サーバーを検証に利用しないことにするということで、気にしないことにしました。(笑) 開発サーバーには要求フィルタリングはなく、例外はすべて ASP.NET で処置されるということなのかもしれません(想像です)。

------ 2011/4/23 追記(2014/4/19 一部訂正) ------

上に書いたとおり、MSDN ライブラリの英語版 Complete Example for Error Handlers にコメントしましたが、それを受けてコードが一部変更されています。(日本語の方は 2011/4/23 現在以前のままですが)

具体的には、Button6 クリックでのリダイレクト先を Global-NoCatch.asax から NonexistentPage-NoCatch.aspx/xxx...(xxx... は x が 500 文字)に変えています。

でも、依然としてダメです。DefaultRedirectErrorPage.aspx にはリダイレクトされません。サーバーは HTTP/1.1 400 Bad Request を返します。


------ 2011/8/22 追記(2014/4/19 一部訂正) ------

MSDN ライブラリの英語版 Complete Example for Error Handlers に書いたコメントはすでに消されていました。また、「日本語の方は 2011/4/23 現在以前のまま」と書きましたが、英語版と同様に修正されていました。

ただし、コードの内容は 2011/4/23 時点の英語版のままです。Button 6 の説明に "Click this button to create an HTTP 400 (invalid url) error. Application_Error will catch this but will not take any action on it, and ASP.NET will redirect to DefaultRedirectErrorPage.aspx." と書いてありますが、そうはなりません。

NonexistentPage-NoCatch.aspx/xxx...(xxx... は x が 500 文字)を要求すると、サーバーは HTTP/1.1 400 Bad Request を返します。web.config の defaultRedirect に指定した DefaultRedirectErrorPage.aspx にはリダイレクトされません。

(HTTP/1.1 400 Bad Request が返ってくると、IE に表示されるのはサーバーから帰ってきた html コードではなく IE が差し替えたものになるので注意してください。Firefox の場合はサーバーから帰ってきた html コードがそのまま表示されます)

ちなみに、以前のように Global-NoCatch.asax にリダイレクトすると、「HTTP エラー 404.7 - Not Found 要求フィルタ モジュールが、ファイル拡張子を拒否するように構成されています。」という標準エラーページが返ってきます。

Tags: ,

Exception Handling

GridView 内の全 CheckBox をオン(jQuery)

by WebSurfer 2010年10月8日 22:11

GirdView の各行に配置した複数の CheckBox に、一度に全部チェックを入れたり外したりする操作を、クライアントサイドのスクリプトで実行する方法の jQuery バージョンです。

普通の JavaScript を使ったバージョンは、先の記事 GridView 内の全 CheckBox をオン にありますので、見比べてみてください。

ネタは先の記事 jQuery の本を買いました で紹介した本の中のサンプルです。

コードは以下の通りです。説明はコードの中にコメントとして入れましたので、そちらを参照してください。

jQuery を使うと、普通の JavaScript を使った場合と比べて、かなりコード量を減らすことができるのは確かのようです。でも、考え方がかなり違うようで、コードの書き方も自分の常識を超えてました。jQuery のセレクタのパワーを垣間見ることができたような気もしますが、正直言って、まだよく分かってないです。(笑)

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  DataTable CreateDataTable()
  {
    DataTable dt = new DataTable();
    DataRow dr;

    dt.Columns.Add(new DataColumn("Item", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Price", typeof(Int32)));

    for (int i = 0; i < 10; i++)
    {
      dr = dt.NewRow();
      dr["Item"] = i;
      dr["Name"] = "Item " + i.ToString();
      dr["Price"] = 123000 * (i + 1);
      dt.Rows.Add(dr);
    }
    return dt;
  }

  void Page_Load(Object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataTable();
      GridView1.DataBind();
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>Check/Uncheck All CheckBoxes in a GridView</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script>
  <script type="text/javascript">
    <!--
    $(function () {
      // ヘッ���ーの CheckBox にチェックを入れる/外すのと連
      // 動して、各行に配置した CheckBox すべてにチェックを
      // 入れる/外す。
      $('table tr th input:checkbox').click(function () {
        $('table tr td input:checkbox')
          .attr('checked', $(this).is(':checked'));
      });

      // 各行に配置した CheckBox のすべてにチェックが入った
      // 時、ヘッダーの CheckBox にもチェックを入れる。
      // 各行に配置した CheckBox の一つでもチェックを外すと、
      // ヘッダーの CheckBox のチェックが外れる。
      $('table tr td input:checkbox').click(function () {
        var chkAll =
          $('table tr td input:checkbox:not(:checked)')
            .length == 0 ? true : false;
        $('table tr th input:checkbox')
          .attr('checked', chkAll);
      });

      // [Check All]ボタンクリックで、すべての CheckBox
      // にチェックを入れる。
      $('#checkAll').click(function () {
        $('table input:checkbox').attr('checked', true);
      });

      // [Uncheck All]ボタンクリックで、すべての CheckBox 
      // のチェックを外す。
      $('#uncheckAll').click(function () {
        $('table input:checkbox').attr('checked', false);
      });
    });            
  //-->
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h2>Check/Uncheck All CheckBoxes</h2>
    <input type="button" 
      id="checkAll"
      value="Check All" /> 
    <input type="button" 
      id="uncheckAll"
      value="Uncheck All" />        
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False">
      <Columns>
        <asp:TemplateField>
          <HeaderTemplate>
            <input id="Checkbox1" type="checkbox" />
          </HeaderTemplate>
          <ItemTemplate>
            <input id="Checkbox2" type="checkbox" />
          </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField HeaderText="Item" DataField="Item" />
        <asp:BoundField HeaderText="Name" DataField="Name" />
        <asp:BoundField HeaderText="Price" DataField="Price" />
      </Columns>
    </asp:GridView>    
  </div>
  </form>
</body>
</html>

------------ 2010/4/24 追記 ------------

この記事で紹介したコードを実際に動かして試せるよう 実験室 にアップしました。興味のある方は試してみてください。

Tags: , ,

JavaScript

GridView 内の全 CheckBox をオン

by WebSurfer 2010年10月7日 23:55

先の 記事で CheckBox にチェックを入れる/外すことによって、当該 CheckBox のテキストのスタイル(文字の色、下線の有無)を変化させる方法を書きました。

今回はその続編(?)として、GirdView の各行に配置した複数の CheckBox に、一度に全部チェックを入れたり外したりする操作を、クライアントサイドのスクリプトで実行する方法を書きます。

GridView 内の全 CheckBox をオン

書きますといっても、コードは 4 Guys From Rolla.com の ページ "Checking All CheckBoxes in a GridView Using Client-Side Script and a Check All" からほぼ丸写しさせてもらったものですが。

[Check All]ボタンをクリックすると、ヘッダーを含むすべての行の CheckBox にチェックが入るようになっています。[Uncheck All]ボタンをクリックすると、すべての行の CheckBox のチェックが外れるようになっています。

ヘッダーの CheckBox にチェックを入れると、各行に配置した CheckBox 全部にチェックが入ります。その状態から、ヘッダーの CheckBox のチェックを外すと、各行の CheckBox のチェックも外れるようになっています。

また、各行に配置した CheckBox に手動で一つ一つチェックを入れていって、すべての CheckBox にチェックが入った時、ヘッダーの CheckBox にもチェックが入るようになっています。その状態から、各行に配置した CheckBox の一つでもチェックを外すと、ヘッダーの CheckBox のチェックも外れるようになっています。

まずは普通の JavaScript を使って書きました。コードは以下の通りです。jQuery を使ってみましたが、かなりコード量を減らすことができるのは確かのようです。別途、jQuery バージョンもアップしますので、乞うご期待。(笑)

コードビハインド

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;

public partial class _051_CheckUncheckAllCheckBoxesInGridView_1_ : System.Web.UI.Page
{
  DataTable CreateDataTable()
  {
    DataTable dt = new DataTable();
    DataRow dr;

    dt.Columns.Add(new DataColumn("Item", typeof(Int32)));
    dt.Columns.Add(new DataColumn("Name", typeof(string)));
    dt.Columns.Add(new DataColumn("Price", typeof(Int32)));

    for (int i = 0; i < 10; i++)
    {
      dr = dt.NewRow();
      dr["Item"] = i;
      dr["Name"] = "Item " + i.ToString();
      dr["Price"] = 123000 * (i + 1);
      dt.Rows.Add(dr);
    }
    return dt;
  }

  void Page_Load(Object sender, EventArgs e)
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataTable();
      GridView1.DataBind();
    }
  }

  protected void GridView1_DataBound(object sender, EventArgs e)
  {
    CheckBox cbHeader =
      (CheckBox)GridView1.HeaderRow.FindControl("CheckBox1");
   cbHeader.Attributes["onclick"] =
      "ChangeAllCheckBoxStates(this.checked);";

    List<string> ArrayValues = new List<string>();
    ArrayValues.Add(String.Concat("'", cbHeader.ClientID, "'"));

    foreach (GridViewRow row in GridView1.Rows)
    {
      CheckBox cb = (CheckBox)row.FindControl("CheckBox2");
      cb.Attributes["onclick"] = "ChangeHeaderAsNeeded();";
      ArrayValues.Add(String.Concat("'", cb.ClientID, "'"));
    }

    CheckBoxIDsArray.Text =
      "<script type=\"text/javascript\">\n" +
      "//<![CDATA[\n" +
      String.Concat("var CheckBoxIDs =  new Array(",
                     String.Join(",", ArrayValues.ToArray()),
                     ");\n"
                   ) +
      "//]]>\n" +
      "</script>";
  }
}

aspx ファイル

<%@ Page Language="C#" AutoEventWireup="true" 
  CodeFile="051_CheckUncheckAllCheckBoxesInGridView(1).aspx.cs" 
  Inherits="_051_CheckUncheckAllCheckBoxesInGridView_1_" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>Check/Uncheck All CheckBoxes in a GridView</title>
  <script type="text/javascript">
    <!--
    function ChangeCheckBoxState(id, checkState) {
      var cb = document.getElementById(id);
      if (cb != null) {
        cb.checked = checkState;
      }
    }

    function ChangeAllCheckBoxStates(checkState) {
      if (CheckBoxIDs != null) {
        for (var i = 0; i < CheckBoxIDs.length; i++) {
          ChangeCheckBoxState(CheckBoxIDs[i], checkState);
        }
      }
    }

    function ChangeHeaderAsNeeded() {
      if (CheckBoxIDs != null) {
        for (var i = 1; i < CheckBoxIDs.length; i++) {
          var cb = document.getElementById(CheckBoxIDs[i]);
          if (!cb.checked) {
            ChangeCheckBoxState(CheckBoxIDs[0], false);
            return;
          }
        }
        ChangeCheckBoxState(CheckBoxIDs[0], true);
      }
    }
    //-->>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h2>Check/Uncheck All CheckBoxes</h2>
    <input type="button" 
      value="Check All" 
      onclick="ChangeAllCheckBoxStates(true);" /> 
    <input type="button" 
      value="Uncheck All" 
      onclick="ChangeAllCheckBoxStates(false);" />
        
    <asp:GridView ID="GridView1" 
      runat="server" 
      AutoGenerateColumns="False" 
      OnDataBound="GridView1_DataBound">
      <Columns>
        <asp:TemplateField>
          <HeaderTemplate>
            <asp:CheckBox runat="server" ID="CheckBox1" />
          </HeaderTemplate>
          <ItemTemplate>
            <asp:CheckBox runat="server" ID="CheckBox2" />
          </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField HeaderText="Item" DataField="Item" />
        <asp:BoundField HeaderText="Name" DataField="Name" />
        <asp:BoundField HeaderText="Price" DataField="Price" />
      </Columns>
    </asp:GridView>
    <asp:Literal ID="CheckBoxIDsArray" runat="server"></asp:Literal>    
  </div>
  </form>
</body>
</html>

--------------- 2010/10/8 追記 ---------------

上記は、普通の JavaScript を使ったものですが、jQuery を使って書き換えたものを別の記事 GridView 内の全 CheckBox をオン(jQuery) にアップしました。jQuery のセレクタのパワーを垣間見たような気がします。ぜひ違いを見てください。

Tags: ,

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar