ASP.NET MVC 3—MvcHandler、MvcHttpHandler

8216 ワード

MVCのソースコードをダウンロードしてデバッグすると、一般的にはMvcHandlerから始まることがわかります.MvcHandlerのコードを簡単に見ると、主にコントローラのファクトリを通じてコントローラのインスタンスを受け入れ、コントローラを使用してさらに処理します.MvcHandlerは作成された場合、どのように呼び出されて実行されますか.
まずMvcHandlerの構造関数を見てみると,無参の構造関数であり,明らかにMvcHandler単独でやるのは少し難しいようだ.MvcHandlerのすべての参照を直接検索すると、MvcRouteHandlerで簡単に見つけることができます.
        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
            requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
            return new MvcHandler(requestContext);
        }

そしてMvcHandler構造関数を使用する場所は一つしかなく、明らかに私たちが望んでいるものを見つけました.
次に、MvcRouteHandlerのGetHttpHandlerがいつ実行されたかを明らかにする必要があります.ソースコードを見ると、「すべての参照を検索する」のが使いやすい機能で、RouteCollectionExtensionsでは次のように見えます.
        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults,
		 object constraints, string[] namespaces) {
            if (routes == null) {
                throw new ArgumentNullException("routes");
            }
            if (url == null) {
                throw new ArgumentNullException("url");
            }
 
            Route route = new Route(url, new MvcRouteHandler()) {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints),
                DataTokens = new RouteValueDictionary()
            };
 
            if ((namespaces != null) && (namespaces.Length > 0)) {
                route.DataTokens["Namespaces"] = namespaces;
            }
 
            routes.Add(name, route);
 
            return route;
        }

これは、MvcRouteHandlerがIrouteHandlerインタフェースを実現するので、Globalにいるときにルーティングモジュールと統合することができることを理解しやすい.AsaxファイルでMapRouteメソッドを使用すると、ルーティングモジュールにMvcRouteHandlerインスタンスが登録され、MvcRouteHandlerが呼び出されるとRequestContextインスタンスが作成されてMvcHandlerインスタンスが生成され、MvcHandlerインスタンスを使用してさらに処理されます.UrlRoutingModuleのコードを表示すると、次のようになります.
 public virtual void PostResolveRequestCache(HttpContextBase context)
    {
        RouteData routeData = this.RouteCollection.GetRouteData(context);
        if (routeData != null)
        {
            IRouteHandler routeHandler = routeData.RouteHandler;
            if (routeHandler == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, 
			SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
            }
            if (!(routeHandler is StopRoutingHandler))
            {
                RequestContext requestContext = new RequestContext(context, routeData);
                context.Request.RequestContext = requestContext;
                IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
                if (httpHandler == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, 
			SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
                }
                if (httpHandler is UrlAuthFailureHandler)
                {
                    if (!FormsAuthenticationModule.FormsAuthRequired)
                    {
                        throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));
                    }
                    UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this);
                }
                else
                {
                    context.RemapHandler(httpHandler);
                }
            }
        }

ここまでMvcHandlerの作成プロセス全体が明らかになっているのではないでしょうか.では、次にMvcHttpHandlerを紹介し続けます.MvcHandlerがある以上、なぜMvcHttpHandlerが必要なのかと聞かれるかもしれません.
実は前述したように,MvcHandlerには無パラメトリックなコンストラクタがないため,MvcHandlerがIHttpHandlerインタフェースを実現してもIISではあるクラスのファイル拡張子のハンドラにマッピングできず,ルーティングモジュールと組み合わせて使用する必要がある.MvcHttpHandlerは、ルーティングモジュールを介さずにマッピングを直接処理する処理プログラムを提供する.
クラスファイル拡張子をMVCプロセッサにマッピングする方法については、ここではあまり説明しないが、MvcHttpHandlerは無参のコンストラクション関数を持ち、UrlRoutingHandlerクラスを継承してIHttpHandlerインタフェースを実現しているため、ASP.NETプログラムでは、いくつかの問題を解決するために柔軟に使用されています.
例えば通常のMVC 3プロジェクトを作成するが、プロジェクトにWebFormページTestPageを追加する.aspx、ページのバックグラウンドファイルTestPage.aspx.csファイルに次のコードを追加します.
        protected void Page_Load(object sender, EventArgs e)
        {
            HttpContext.Current.RewritePath("/Home/About");
            IHttpHandler httpHandler = new MvcHttpHandler();
            httpHandler.ProcessRequest(HttpContext.Current);
        }

そして直接/TestPageにアクセスします.aspxページでは、実際のアクセスが/Home/Aboutページに戻っていることがわかります.
デバッグアクセス/TestPage.aspxが実行するプロセスでは、最終的にはMvcHandlerが使用されていることがわかりますが、なぜそうなったのでしょうか.興味があればUrlRoutingHandlerのProcessRequestの論理を見れば理解できます.