58 votes

Pourquoi mon gestionnaire d'événement 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 fichier de type EndRequest dans un gestionnaire d'événement imbriqué HttpModule 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 module imbriqué HttpModule jamais de feu, même si je sais Init a été appelé sur les éléments imbriqués HttpModule .

Ma question est la suivante : qu'est-ce qui se passe dans mon code ci-dessous pour empêcher l'en-tête "TestNested" d'apparaître dans les en-têtes de réponse, à moins que je n'inclue le code commenté qui ajoute une balise de type EndRequest un gestionnaire d'événement 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 premier niveau

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 EndRequest gestionnaire d'événement

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
        }
    }
}

13 votes

Je suppose que la question évidente est la suivante : pourquoi utilisez-vous un HttpModule pour changer les en-têtes au lieu d'utiliser des API MVC telles que filtres pour faire ça ? Pourquoi utiliser une technologie ASP.NET ancienne et complexe pour quelque chose qui est déjà facilement modifiables dans MVC ?

1 votes

Quelle version d'Asp.Net MVC et du framework .NET utilisez-vous ? Le NestedHttpModule.EndRequest se déclenche pour moi.

0 votes

@CodingDawg MVC 5.2.2 et .NET 4.6.2

1voto

JohnnBlade Points 2713

Je voulais aussi modifier mes en-têtes, mais je devais en cacher le plus possible. C'est la même chose pour Ajouter ou Supprimer ou les deux, ce sont juste des en-têtes.

1) Vous pouvez définir MvcHandler.DisableMvcResponseHeader = true; dans le fichier 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) Il ne faut pas vraiment utiliser le module diff pour faire quasiment le même travail, mais plutôt créer un module HeadersModule qui ne s'occupe que de la modification de l'en-tête, et utiliser l'option PreSendRequestHeaders pour ajouter ou supprimer les en-têtes que vous souhaitez. 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 ajouter ceci à 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, c'est-à-dire les pages 404, les pages d'erreur, les noms de chemin bizarres, car elles peuvent laisser échapper certains en-têtes ou afficher des en-têtes que vous n'attendiez pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X