WebSurfer's Home

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

jQuery.ajax を使っての事前検証

by WebSurfer 2022年2月6日 15:56

ASP.NET Web Forms アプリで jQuery Ajax を使ってポストバックの際にサーバー側で行われる処理が可能かどうかを事前に調べ、可能と分かったら JavaScript で Button クリックしてポストバックする、可能ではないと分かった場合はポストバックせずメッセージを表示してユーザーに知らせるという話です。

ポストバックして処理完了

元の話は Teratail のスレッド「asp:button 押下前にサーバサイドが応答しているか確認したいためPingのようなことを行いたい」のものです。実際のそのような検証が必要なケースはあまりなさそうですが、せっかく考えた話ですし jQuery Ajax の timeout の使い方が今後の参考になるかもしれないと思ったので備忘録として書いておくことにしました。

Button クリックでポストバックしてサーバー側でユーザーが送信したデータを受けて、データベースサーバーにクエリを投げる等の処理をすることはよくあると思います。

その際、Button クリックでいきなりポストバックするのではなく、その前に jQuery Ajax を使って事前にサーバー側での処理が可能かどうかを調べるというストーリーです。

(いきなりポストバックしても結果をきちんとユーザーに知らせることはできるし、やりすぎるとサーバーに無駄な負荷を増やすし軽くすると検証の意味が薄れるということで、そのような検証の必要性は低いとは思いますがそこは置いときます)

jQuery Ajax で呼び出してサーバー側で事前検証を行う HTTP ジェネリックハンドラを作ります。以下のコードがそのサンプルです。

HTTP ジェネリックハンドラ Handler1.ashx

using System.Web;

namespace WebForms1
{
    public class Handler1 : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            // Button クリックでポストバックされた時にサーバー
            // で行われる処理が可能か事前に検証する。処理に最
            // 長 3 秒かかるとして、ここでは単純に 3 待つ
            System.Threading.Thread.Sleep(3000);
            
            // 検証に成功したら "検証成功" という文字列を返す
            var validationResult = "検証成功";

            context.Response.ContentType = "text/plain";
            context.Response.Write(validationResult);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

上の Handler1.ashx を jQuery Ajax を使って呼び出します。Handler1.ashx は検証に成功すると "検証成功" という文字列を返すので、それを受けたら JavaScript で Button をクリックしてポストバックします。その結果がこの記事の一番上にある画像です。

Handler1.ashx を呼び出す JavaScript を含む Web Form ページのサンプルコードは以下の通りです。

WebForm1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs"
    Inherits="WebForms1.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <script src="Scripts/jquery-3.4.1.js"></script>
    <script type="text/javascript">
        $(function () {
            $("#btnSec").on("click", function () {
                $.ajax({
                    type: "get",
                    url: "Handler1.ashx",
                    timeout: 5000
                }).done(function (data) {
                    // 呼び出し先 Handler1.ashx で検証が成功すると "検証成功" 
                    // という文字列が返ってきて引数 data に代入される
                    if (data == "検証成功") {
                        var hiddenbutton = document.getElementById("Button1");
                        // Button をクリック
                        hiddenbutton.click();
                    } else {
                        $("#Label1").text("処理できません - 検証結果 NG");
                    }
                }).fail(function (jqXHR, textStatus, errorThrown) {
                    $("#Label1").text("処理できません - " + textStatus);
                });
            });
        });
    </script>
    <style type="text/css">
        .style1
        {
            display: none;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <h2>WebForm1 - jQuery.Ajax を使っての事前検証</h2>
            
            <input id="btnSec" type="button" value="反映" />

            <%--ポストバックを行う Button コントロール。上の style1 で
                隠しボタンに設定。クリックは JavaScript で行う。クリ
                ックされるとポストバックが発生し、サーバー側のイベント
                ハンドラ ClickBtnSection で必要な処理が行われる--%>
            <asp:Button ID="Button1" runat="server" 
                OnClick="ClickBtnSection" CssClass="style1" />

            <asp:Label ID="Label1" runat="server">
                Label1 初期値
            </asp:Label>
        </div>
    </form>
</body>
</html>

WebForm1.aspx.cs

using System;

namespace WebForms1
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void ClickBtnSection(object sender, EventArgs e)
        {
            // サーバー側での必要な処理

            Label1.Text = "Button1 がクリックされました";
        }
    }
}

Handler1.ashx を呼び出して、そこでの処理中にサーバーエラーが発生した場合は以下のようになります。

サーバーエラー

Handler1.ashx を呼び出した後、jQuery Ajax の timeout オプションに設定した時間(上のコード例では 5 秒)待っても応答が返ってこない場合は以下のようになります。

timeout

Handler1.ashx から帰ってきた文字列が "検証成功" 以外の場合は(実際にそういうケースはないかもしれませんが)以下のようになります。

検証結果 NG

Tags: , , ,

Validation

Forms 認証のタイムアウト判定

by WebSurfer 2010年7月30日 08:37

あまり役に立たないかもしれませんが、ASP.NET 標準の Forms 認証システムで、認証チケットが期限切れになっているかどうかを判定するという話です。なお、前提条件としてクッキーが有効になっていることを想定しています。

例えば、一旦認証を受けたユーザーが、ログオフせず、ブラウザを立ち上げたまま、長時間席を外すなどして、タイムアウトに設定した時間を超えてアクセスしなかった場合を考えてください。

ユーザーが席に戻ってきて再度アクセスした場合、アクセスしたページに匿名アクセスを許可してなければ、ログインページにリダイレクトされるというのが Forms 認証の通常の設定です。

そこで、ユーザーに認証チケットが期限切れとなっていることを知らせるにはどうしたらいいでしょうか?

User.Identity.IsAuthenticated ではダメです。認証されているか否かは判定できますが、認証チケットが期限切れかどうかはわかりませんから。

一旦認証を受けたが、認証チケットが期限切れになっているというのは、サーバー側では以下の条件で判定できるはずです。

  • 要求 HTTP ヘッダーに認証クッキーが含まれる。
  • 認証クッキーの中の認証チケットが期限切れ。

認証クッキーと認証チケットは違うことに注意してください。クッキーはチケットの入れ物に過ぎません。認証チケットの有効期限は、認証クッキーの Value の中に入っている情報の一つです。HttpCookie.Expires ではありません。

一般的に、一旦認証クッキーの発行を受ければ、セッションが切れない限り(注)、次の要求の時にブラウザはサーバーにクッキーを送ります。(注:認証クッキーを「永続化」している場合は話が違ってきます。詳しくは別の記事「Froms 認証クッキーの永続化」を見てください)

認証クッキーを取得し、その Value を復号して認証チケットを取得し、ユーザー名、期限切れか否かなどの情報を取得できます。それで上記の 2 つの条件を確認できます。例えば、ログインページにリダイレクトされたときに期限切れを知らせる場合は、Global.asax で以下のようにします(もしくは HTTP Module を作る)。

void FormsAuthentication_Authenticate(object sender, 
  FormsAuthenticationEventArgs args)
{
  // "/login.aspx" は実際に合わせて適宜変更してください。
  if (Request.CurrentExecutionFilePath != "/login.aspx")
  {
    return;
  }

  string cookieName = FormsAuthentication.FormsCookieName;
  HttpCookie authCookie = Context.Request.Cookies[cookieName];

  if (null == authCookie)
  {
    return;
  }

  FormsAuthenticationTicket authTicket = null;
  try
  {
    authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  }
  catch (Exception ex)
  {
    return;
  }

  if (null == authTicket)
  {
    return;
  }

  if (authTicket.Expired)
  {
    // 知らせるための処置を書く。例えば下記:
    Context.Response.Write("<h1><font color=red>" +
      "Forms Authentication Ticket Expired" +
      "</font></h1><hr>");
  }
}

認証チケットが期限切れの場合、FormsAuthenticationModule が認証クッキーを削除しているようで、タイミングによっては認証クッキーは取得できないので注意してください。

従って、認証クッキーを取得できるのは、FormsAuthenticationModule.Authenticate イベント以前のタイミングになります。

Tags: ,

Authentication

About this blog

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

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar