Pergunta

Recentemente, enquanto trabalhava em algum código para um projeto ASP.NET no trabalho. Precisávamos de um rastreamento util para tomar métricas básicas sobre a atividade do usuário (página Contagem etc) que iria acompanhá-los no Session , em seguida, salvar os dados em DB via Session_End em Global.asax .

Eu comecei a mexer, o código inicial funcionou bem, atualizando o DB em cada carregamento da página. Eu queria remover esse DB impactos em cada solicitação embora e confiar apenas em Session_End para armazenar todos os dados.

Todo o código de rastreamento é encapsulado na classe Tracker, incluindo propriedades que essencialmente envolvem as variáveis ??de sessão.

O problema é que quando eu executado Tracker.Log() no método Session_End, a HttpContext.Current.Session no código tracker foi falhando com um NullReferenceException . Agora, isso faz sentido, pois HttpContext sempre se relaciona com a atual pedido, e, claro, em Session_End, não há nenhuma solicitação.

Eu sei que Global.asax tem uma propriedade Session que retorna um HttpSessionState que realmente parece funcionar bem (eu acabei injetá-lo no para o tracker) ..

Mas estou curioso, como diabos eu posso obter a mesma referência ao objeto HttpSessionState usado por Global.asax de fora de Global.asax?

Agradecemos antecipadamente caras, eu aprecio a entrada. :)

Foi útil?

Solução

Global.asax implementos HttpApplication -. Que é o que você está falando quando você chamar este de dentro dele

A documentação do MSDN para HttpApplication tem detalhes sobre como você pode se apossar dela em um HttpHandler por exemplo, e em seguida, obter acesso às várias propriedades do mesmo.

NO ENTANTO

O aplicativo pode criar várias instâncias de HttpApplication para lidar com solicitações paralelas, e essas instâncias podem ser, então, basta pegá-la de alguma forma não vai guarentee que você tem o direito reutilizado.

também eu também adicionar uma nota de cautela - se o seu aplicativo falha, não há guarentee que Session_End vai ser chamado, e você terá perdido todos os dados em todas as sessões, claramente não é uma coisa boa

Eu concordo que a exploração madeireira em todas as páginas provavelmente não é uma grande idéia, mas talvez uma casa de recuperação com alguns logs assíncrona acontecendo - você fogo detalhes off a uma classe de registro, que a cada momento e, em seguida, registra os detalhes que são depois - ainda não é 100% sólido se as falhas de aplicativos, mas você é menos provável a tudo perder.

Outras dicas

Para responder à pergunta original melhor:

Fundo

Cada solicitação de página gira-se um novo objeto Session e depois enche-lo de sua loja de sessão. Para fazer isso, ele usa o cookie fornecido pelo cliente ou uma construção caminho especial (para sessões cookieless). Com este identificador de sessão, ele consulta o armazenamento de sessão e desserializa (é por isso que todos os fornecedores, mas InProc necessidade de ser Serializable) o novo objeto de sessão.

No caso do provedor InProc, apenas entrega-lhe a referência armazenado na sua HttpCache introduzidos pelo identificador de sessão. É por isso que o provedor InProc cai estado da sessão quando o AppDomain é reciclado (e também por vários servidores web pode não estado compartilhamento de sessão InProc .

Este recém-criado e objeto inflado está preso na coleção Context.Items para que ele esteja disponível para a duração do pedido.

Todas as alterações feitas ao objeto Session são, então, persistiu no final da solicitação para o armazenamento de sessão, serialização (ou no caso de InProc, a entrada HttpCache é atualizado).

Desde incêndios Session_End sem um pedido atual em-fly, o objeto Session é girado até ex-nilo, com nenhuma informação disponível. Se estiver usando o estado da sessão InProc, a expiração do HttpCache desencadeia um evento de retorno de chamada para o seu evento Session_End, então a entrada sessão está disponível, mas ainda é uma cópia do que foi passado armazenado no HttpContext.Cache. Este valor é armazenado contra a propriedade HttpApplication.Session por um método interno (chamado ProcessSpecialRequest), onde ele estará disponível. Sob todos os outros casos, se trata internamente a partir do valor HttpContext.Current.Session.

A sua resposta

Uma vez que o Session_End dispara sempre contra um contexto nulo, você deve sempre usar this.Session nesse caso e passar o HttpSessionState opor-se ao seu código de rastreamento. Em todos os outros contextos, é perfeitamente bem para buscar a partir HttpContext.Current.Session e depois passar para o código de rastreamento. não , no entanto, que o código de rastreamento atingir até para o contexto sessão.

A minha resposta

Não use Session_End menos que você saiba que o armazenamento de sessão que você está usando oferece suporte Session_End, que não se retorna true de SetItemExpireCallback. A loja só in-the-box que faz é a loja InProcSessionState. É possível escrever um armazenamento de sessão que faz, mas a questão de quem irá processar o Session_End é uma espécie de ambíguo, se houver vários servidores.

Eu acho que você já respondeu à sua própria pergunta: normalmente, propriedade Session no Global.asax e HttpContext.Current.Session são os mesmos (se houver um pedido atual). Mas, no caso de um tempo limite da sessão, não há pedido ativo e, portanto, você não pode usar HttpContext.Current.

Se você quiser acessar a sessão a partir do método chamado por Session_End, em seguida, passá-lo como um parâmetro. Criar um método Log () versão sobrecarregada, o que leva um HttpSessionState como um parâmetro, em seguida, chamar Tracker.Log (this.Session) do manipulador de eventos Session_End.

BTW: você está ciente que você não pode confiar no evento final da sessão, em qualquer caso? Ele só vai funcionar enquanto você tem o estado da sessão no processo. Ao usar o servidor SQL ou StateServer para gerenciar o estado da sessão, o evento final da sessão não irá fogo.

O evento Session_End é levantada apenas quando o sessionstate mode está definido para InProc no arquivo Web.config. Se o modo de sessão está definido para StateServer ou SQLServer, o evento não é gerado.

uso Session["SessionItemKey"] para obter o valor da sessão.

Ok, eu estou no mesmo problema para rastrear a atividade da sessão. Em vez de usar evento Session_End, eu implementei a interface IDisposable e destrutor para minha classe sessiontracker. Eu modifiquei o método Dispose () para salvar a atividade da sessão para DB. Invoquei o método obj.Dispose () quando um usuário clica no botão de logout. Se o usuário fechou o navegador por engano, então GC irá chamar o destruidor durante a limpeza dos objetos (e não imediatamente, mas com certeza ele vai chamar esse método depois de algum tempo). O método destrutor executar internamente o mesmo método Dispose () para salvar as atividades da sessão em DB.

-Shan

Session está disponível no seu arquivo global, durante o evento Session_Start. Talvez esperar até este ponto para fazer coisas?

Lembre-se que Session_End é executado quando a sessão sem atividade. O navegador não se origina esse evento (porque é inativo), então a única vez que você realmente vai ter o evento é ao usar o provedor InProc. Em todos os outros provedor, este evento jamais fogo.

Moral? Não use Session_End.

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