ASP.NET MVC で ページ遷移 を 記録する フィルター

0 件のコメント

ブラウザでどのようにページ遷移が行われたかを簡単に記録するためのフィルターを作成します。

このフィルターを利用することで「不適切なページ遷移を拒否できる」とか「ブラウザの戻る機能の無効化」 ができるようになることを目指します。

ソースコード

閲覧履歴をセッションに残すフィルターを作成します。 ここでは Filters フォルダ & 名前空間を1つ掘って実装しています。

BrowsingHistoryAttribute.cs

namespace SampleMvcApplication.Filters
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;

    /// <summary>
    /// 閲覧履歴をセッションに記録するフィルター属性を表します。
    /// </summary>
    public class BrowsingHistoryAttribute : FilterAttribute, IActionFilter
    {
        /// <summary>
        /// 直前に閲覧したURLをセッションに保存するキー文字列
        /// </summary>
        public static string PREVIOUS_URL = "PREVIOUS_URL";

        /// <summary>
        /// 現在要求されたURLをセッションに保存するキー文字列
        /// </summary>
        public static string CURRENT_URL = "CURRENT_URL";

        /// <summary>
        /// アクション結果の実行後に ASP.NET MVC フレームワークによって呼び出されます。
        /// </summary>
        /// <param name="filterContext">フィルター コンテキスト</param>
        public void OnActionExecuted(ActionExecutedContext filterContext)
        {
        }

        /// <summary>
        /// アクション結果の実行前に ASP.NET MVC フレームワークによって呼び出されます。
        /// </summary>
        /// <param name="filterContext">フィルター コンテキスト</param>
        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // 必要な変数を取得
            var httpContext = filterContext.HttpContext;
            var session = httpContext.Session;
            var request = httpContext.Request;

            // POST と Ajax リクエスト は記録しない
            if (request.HttpMethod == "POST" || request.IsAjaxRequest())
            {
                return;
            }

            // リクエストURL を正規化
            var url = this.GetNormalizedRequestUrl(httpContext);

            // 閲覧履歴を更新
            session[PREVIOUS_URL] = session[CURRENT_URL];
            session[CURRENT_URL] = url;
        }

        /// <summary>
        /// リクエストURLを正規化します
        /// </summary>
        /// <param name="httpContext">HTTP コンテキスト</param>
        /// <returns>正規化された リクエストURL</returns>
        private string GetNormalizedRequestUrl(HttpContextBase httpContext)
        {
            var routeData = System.Web.Routing.RouteTable.Routes.GetRouteData(httpContext);
            var controllerName = routeData.Values["controller"].ToString().ToLower();
            var actionName = routeData.Values["action"].ToString().ToLower();
            var queryString = httpContext.Request.QueryString.ToString();

            if (string.IsNullOrEmpty(queryString))
            {
                return string.Format("{0}/{1}", controllerName, actionName);
            }
            else
            {
                return string.Format("{0}/{1}?{2}", controllerName, actionName, queryString);
            }
        }
    }
}

説明

フィルターなので FilterAttributeクラス の継承を行います。 今回のフィルターはできるだけ早いタイミングで実施したいので、IActionFilterインターフェース の実装を行っています。

.OnActionExecuting で セッション に対して閲覧履歴を更新しにかかります。 POST と Ajax リクエストは保存しないように処理されています。

.OnActionExecuted は特に必要な処理がないので何も記述しない空のメソッドになります。

リクエストURLはショートカットされる場合(MapPathに登録されていたり、IndexのようにIISに登録されていたりする場合)があるので、 .GetNormalizedRequestUrl 関数を利用してキチンとしたURLへ再マッピングしなおしています。 この関数にかんする詳細は こちら の記事をご参照ください。

使用例

上記ソースコードで記述した属性を利用してみます。 以下のサンプルコードでハイライトされた部分が利用例となります。 Controller クラス に対して属性をつけることで、そのクラスのメソッドすべてに対して履歴を取るようにしています。

サンプルコード

namespace SampleMvcApplication.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using SampleMvcApplication.Filters;

    [BrowsingHistory]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return this.View();
        }

        public ActionResult Login()
        {
            return this.View();
        }

        public ActionResult Index2()
        {
            return this.View();
        }
    }
}