Pergunta

Eu estava criando um módulo HTTP e, durante a depuração, notei algo que a princípio (pelo menos) parecia um comportamento estranho.

Quando eu defino um ponto de interrupção no método init do httpmodule, posso ver que o método init do módulo HTTP está sendo chamado várias vezes, apesar de eu ter iniciado o site para depuração e fiz uma única solicitação (às vezes é atingida apenas 1 vez , outras vezes mais 10 vezes).

Sei que devo esperar que várias instâncias da httpplication estejam em execução e, para cada um, os módulos HTTP serão criados, mas quando solicitar uma única página, ele deve ser tratado por um único objeto de aplicativo HTTP e, portanto, demitir apenas os eventos associados uma vez, uma vez, Mas ainda assim dispara os eventos várias vezes para cada solicitação, o que não faz sentido - além de ter sido adicionado várias vezes dentro dessa httpplication - o que significa que é o mesmo método HTTPModule init que está sendo chamado toda vez e não um novo aplicativo HTTP sendo criado cada vez que atinge meu ponto de interrupção (veja meu exemplo de código na parte inferior etc.).

O que poderia estar dando errado aqui? É porque estou depurando e defino um ponto de interrupção no módulo HTTP?

Ele percebeu que parece que, se eu iniciar o site para depuração e passar rapidamente pelo ponto de interrupção no httpmodule, ele apenas atingirá o método init uma vez e o mesmo vale para o EventHandler. Se, em vez disso, eu o deixar pendurar no ponto de interrupção por alguns segundos, o método init está sendo chamado várias vezes (parece que depende de quanto tempo espero antes de passar pelo ponto de interrupção). Talvez isso possa ser um recurso de construção para garantir que o httpmodule seja inicializado e o aplicativo HTTP possa atender solicitações, mas também parece algo que pode ter consequências catastróficas.

Isso pode parecer lógico, pois pode estar tentando terminar a solicitação e, como eu defini o ponto de interrupção, acha que algo deu errado e tenta chamar o método init novamente? Então, ele pode lidar com a solicitação?

Mas é isso que está acontecendo e está tudo bem (estou apenas adivinhando), ou é um problema real?

O que estou especialmente preocupado é que, se algo o faz pendurar no servidor "Produção/Live" por alguns segundos, muitos manipuladores de eventos são adicionados através do init e, portanto, cada solicitação à página de repente dispara o EventHandler várias vezes.

Esse comportamento pode diminuir rapidamente qualquer site.

Eu olhei para o código "Original" .NET usado para os httpmodules para formação de autenticação e o rolemanagermodule etc, mas meu código não é diferente que esses módulos use.

Meu código se parece com isso.

    public void Init(HttpApplication app)
    {
        if (CommunityAuthenticationIntegration.IsEnabled)
        {
            FormsAuthenticationModule formsAuthModule = (FormsAuthenticationModule) app.Modules["FormsAuthentication"];         

            formsAuthModule.Authenticate += new FormsAuthenticationEventHandler(this.OnAuthenticate);
        }
    }

Aqui está um exemplo de como é feito no rolemanagermodule da estrutura .NET

    public void Init(HttpApplication app)
    {
        if (Roles.Enabled)
        {
            app.PostAuthenticateRequest += new EventHandler(this.OnEnter);
            app.EndRequest += new EventHandler(this.OnLeave);
        }
    }

Alguém sabe o que está acontecendo?

(Eu só espero que alguém lá fora possa me dizer por que isso está acontecendo e me garantir que tudo está perfeitamente bem) :)


ATUALIZAR:

Tentei restringir o problema e até agora descobri que o método init que está sendo chamado está sempre em um novo objeto do meu módulo HTTP (contário do que eu pensava antes).

Parece que, para a primeira solicitação (ao iniciar o site), todos os objetos HTTPApplication que estão sendo criados e seus módulos estão tentando servir a primeira solicitação e, portanto, todos atingem o EventHandler que está sendo adicionado. Eu realmente não consigo descobrir por que isso está acontecendo.

Se eu solicitar outra página, todas as httpplication criadas (e sua modula) tentarão novamente servir a solicitação, fazendo com que ele atinja o EventHandler várias vezes.

Mas também parece que, se eu voltar para a primeira página (ou outra), apenas uma httpplication começará a cuidar da solicitação e tudo é o esperado - desde que eu não o deixe ficar em um ponto de interrupção.

Se eu deixar pendurar em um ponto de interrupção, começará a criar novos objetos da HttPapplication e começar a adicionar httpapplications (mais de 1) para servir/lidar com a solicitação (que já está em processo de ser servido pela httpplication que está atualmente interrompida no ponto de interrupção) .

Eu acho ou espero que seja uma maneira inteligente "nos bastidores" de ajudar a distribuir e lidar com carga e / ou erros. Mas eu não tenho idéia. Espero que alguns por aí possam me garantir que está perfeitamente bem e como deveria ser?

Foi útil?

Solução

  1. Inspecione o httpcontext.current.request para ver, para que solicitação o init do módulo seja demitido. Pode ser o navegador enviando várias solicitações.

  2. Se você estiver conectado ao IIS, verifique os logs do IIS para saber se alguma solicitação é recebida pelo tempo em que você ficará no ponto de interrupção.

Outras dicas

É normal que o método init () seja chamado várias vezes. Quando um aplicativo é iniciado, o processo do trabalhador do ASP.NET instanciará tantos objetos de httpplication quanto achar que precisa, então os agrupará (por exemplo, os retuem para novas solicitações, semelhante ao pool de conexões do banco de dados).

Agora, para cada objeto httpApplication, ele também instanciará uma cópia de cada iHttpmodule registrado e chama o método init que muitas vezes. Portanto, se 5 objetos de httpApplication forem criados, 5 cópias do seu iHttpmodule serão criadas e seu método init chamado 5 vezes. Faz sentido?

Agora, por que está instanciando 5 objetos de httpapplications? Bem, talvez sua página ASPX tenha links para outros recursos que seu navegador tentará baixar, CSS, JavaScript, webresource.aspx, talvez um iframe em algum lugar. Ou talvez o processo do trabalhador do ASP.NET 'esteja no clima' para iniciar mais de 1 objeto HTTPAPplication, esse é realmente um detalhe/otimização interno do processo ASP.NET em execução no IIS (ou o VS Built in In WebServer).

Se você deseja que o código seja executado apenas uma vez (e não deseja usar o evento Application_Startup no global.asax), você pode tentar o seguinte no seu iHttpmodule:

private static bool HasAppStarted = false;
private readonly static object _syncObject = new object();

public void Init(HttpApplication context)
{
    if (!HasAppStarted)
    {
        lock (_syncObject)
        {
            if (!HasAppStarted)
            {
                // Run application StartUp code here

                HasAppStarted = true;
            }
        }
    }
}

Eu fiz algo semelhante e parece funcionar, embora eu tenha recebido críticas ao meu trabalho, caso eu tenha perdido alguma coisa.

Exame acima bloqueia o iHttpmodule para todas as solicitações e, em seguida, ele frequenta todo o aplicativo. Se a sua solicitação de IHTTPModule é necessária várias vezes para ligar para o método de httPapplication, completar e descartar a instância de httpplication do iHttpmodule em EndRequest Event para remover a instância da httpApplication como esta:

public class TestModule :IHttpModule
    {
        #region IHttpModule Members

        public void Dispose()
        {

        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            app.CompleteRequest();
            app.Dispose();
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            //your code here
        }

        #endregion
    }

Se você precisar que o IHTTPMODULE solicite sempre que o Rerequest no postback use este código acima.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top