web-dev-qa-db-fra.com

Pourquoi mon gestionnaire d'événements HttpModule EndRequest imbriqué ne se déclenche-t-il pas?

J'ai un comportement étrange lorsque j'essaie de modifier mes en-têtes avec un gestionnaire d'événements EndRequest dans un HttpModule imbriqué sur MVC 5.2.2 et .NET 4.6.2. Si je ne modifie pas EndRequest dans mon niveau supérieur HttpModule, il semble que le gestionnaire d'événements dans le HttpModule imbriqué ne se déclenche jamais, même si je sais Init a été appelé sur le HttpModule imbriqué.

Ma question est, que se passe-t-il dans mon code ci-dessous pour empêcher l'en-tête "TestNested" d'apparaître dans les en-têtes de réponse, sauf si j'inclus le code commenté qui ajoute un gestionnaire d'événements EndRequest qui ne fait rien?


Enregistrer dynamiquement mon niveau supérieur HttpModule

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

Appelez Init sur tous mes autres HttpModules à partir d'un seul module de niveau supérieur

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();
            }
        }
    }
}

Modifier certaines informations d'en-tête dans un gestionnaire d'événements 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

Je voulais également modifier mes en-têtes, mais je devais cacher autant que possible. C'est la même chose pour Ajouter ou Supprimer ou les deux, ce ne sont que des en-têtes.

1) Vous pouvez définir MvcHandler.DisableMvcResponseHeader = true; dans le 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) Vous ne devriez pas vraiment utiliser le module diff pour presque le même travail, créez plutôt un HeadersModule qui ne gère que la modification des en-têtes, et utilisez le PreSendRequestHeaders pour ajouter ou supprimer les en-têtes souhaités. Vous pouvez toujours injecter un service avec une liste d'en-têtes à ajouter ou à supprimer.

    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) Pour être encore plus sûr, que certains en-têtes s'affichent ou "ne s'affichent pas", vous pouvez l'ajouter à votre fichier de configuration

  <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) Testez toutes les pages, alias 404, les pages d'erreur, les noms de chemin étranges, car ils peuvent fuir certains en-têtes ou afficher des en-têtes auxquels vous ne vous attendiez pas.

1
JohnnBlade