web-dev-qa-db-ja.com

ネストされたHttpModule EndRequestイベントハンドラーが起動しないのはなぜですか?

MVC 5.2.2および.NET 4.6.2で、ネストされたEndRequestHttpModuleイベントハンドラーでヘッダーを変更しようとすると、奇妙な動作をします。トップレベルEndRequestHttpModuleを変更しない場合、HttpModuleが呼び出されたことがわかっていても、ネストされたInitのイベントハンドラーは起動しませんネストされたHttpModule

私の質問は、何もしないEndRequestイベントハンドラーを追加するコメントアウトされたコードを含めない限り、応答ヘッダーに「TestNested」ヘッダーが表示されないようにするために、以下のコードで何が起こっているのですか?


最上位レベルを動的に登録するHttpModule

[Assembly: PreApplicationStartMethod(typeof(PreApplicationStartClass), "Start")]
namespace MyNamespace
{
    public class PreApplicationStartClass
    {
        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(TopHttpModule));
        }
    }
}

単一のトップレベルモジュールから他のすべてのInitHttpModulesを呼び出す

namespace MyNamespace
{
    public class TopHttpModule: IHttpModule
    {
        private readonly Lazy<IEnumerable<IHttpModule>> _modules = 
            new Lazy<IEnumerable<IHttpModule>>(RetrieveModules);

        private static IEnumerable<IHttpModule> RetrieveModules()
        {
            return DependencyResolver.Current.GetServices<IHttpModule>();
        }

        public void Init(HttpApplication context)
        {
            var modules = _modules.Value;
            foreach (var module in modules
                .Where(module => module.GetType() != typeof(TopHttpModule)))
            {
                module.Init(context);
            }

            context.BeginRequest += (sender, e) =>
            {
                var app = sender as HttpApplication;
                if (app != null)
                {
                    //This shows that NestedHttpModule was found
                    app.Context.Response.Headers.Add(
                        "TestModules",
                        string.Join(",", modules.Select(_ => _.GetType().ToString())));
                }
            };

            //Add this and the NestedHttpModule EndRequest handler works
            //context.EndRequest += (sender, e) =>
            //{
            //    //Do Nothing
            //};
        }

        public void Dispose()
        {
            var modules = _modules.Value;
            foreach (var disposable in modules
                .Where(disposable => disposable.GetType() != typeof(TopHttpModule)))
            {
                disposable.Dispose();
            }
        }
    }
}

EndRequestイベントハンドラーのヘッダー情報を変更します

namespace MyNamespace
{
    public class NestedHttpModule: IHttpModule
    {
        public void Init(HttpApplication context)
        {
            //This gets called whether or not the TopHttpModule modifies context.EndRequest 
            MvcHandler.DisableMvcResponseHeader = true;

            context.EndRequest += Application_EndRequest;
        }

        public void Application_EndRequest(object sender, EventArgs e)
        {
            var app = sender as HttpApplication;
            if (app != null && app.Context != null)
            {
                //This doesn't appear to be called unless TopHttpModule modifies context.EndRequest
                app.Context.Response.Headers.Add("TestNested", "Found");
            }
        }

        public void Dispose()
        {
            //Do Nothing
        }
    }
}
59
Thomas Langston

ヘッダーも変更したかったのですが、できるだけ隠す必要がありました。追加または削除、あるいはその両方で同じであり、単なるヘッダーです。

1)MvcHandler.DisableMvcResponseHeader = true; global.asax内

        protected void Application_Start()
        {
            MvcHandler.DisableMvcResponseHeader = true;
        }

and

        protected void Application_PreSendRequestHeaders()
        {
            Response.Headers.Remove("Server");
            Response.Headers.Remove("X-AspNet-Version");
        }

2)ほぼ同じジョブにdiffモジュールを実際に使用するのではなく、ヘッダーの変更のみを処理するHeadersModuleを作成し、PreSendRequestHeadersを使用して必要なヘッダーを追加または削除します。追加または削除するヘッダーのリストを使用して、いつでもサービスを挿入できます。

    public class HeadersModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.PreSendRequestHeaders += OnPreSendRequestHeaders;
        }

        public void Dispose() {

        }

        void OnPreSendRequestHeaders(object sender, EventArgs e)
        {

            var r = sender as HttpApplication;
            r.Response.Headers.Remove("Server");
            r.Response.Headers.Remove("X-AspNetMvc-Version");
            r.Response.Headers.Remove("X-AspNet-Version");
            r.Response.Headers.Remove("X-Powered-By");
        }
    }

3)さらに確実にするために、一部のヘッダーが表示される、または「表示されない」ことを構成ファイルに追加できます

  <system.webServer>
    <modules>
      <add name="HeadersModule " type="MyNamespace.Modules.HeadersModule " />
    </modules>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
        <remove name="Server" />
        <remove name="X-AspNet-Version" />
        <remove name="X-AspNetMvc-Version" />
      </customHeaders>
      <redirectHeaders>
        <clear />
      </redirectHeaders>
    </httpProtocol>
  </system.webServer>

4)すべてのページ(別名404、エラーページ、奇妙なパス名)をテストします。特定のヘッダーがリークしたり、予期しないヘッダーが表示されたりする可能性があります。

1
JohnnBlade