Como posso implementar um padrão robusto de sessão por solicitação no meu projeto, enquanto focalizando as informações escondidas?

StackOverflow https://stackoverflow.com/questions/2046168

Pergunta

Atualmente, estou construindo um projeto ASP.NET MVC, com o Nibernate como sua camada de persistência.

Por enquanto, algumas funcionalidades foram implementadas, mas usam apenas sessões locais de Nibernate: cada método que acessou o banco de dados (leia ou gravação) precisa instanciar sua própria sessão Nibernate, com a cláusula "Usando ()".

O problema é que quero aproveitar os recursos de carregamento preguiçoso da Nhibernate para melhorar o desempenho do meu projeto.

Isso implica uma sessão aberta de Nibernate por solicitação até que a visualização seja renderizada. Além disso, solicitações simultâneas devem ser suportadas (várias sessões ao mesmo tempo).

Como posso conseguir isso o mais limpo possível?

Eu procurei um pouco na web e aprendi sobre o padrão de sessão por solicitação. A maioria das implementações que vi usou algum tipo de http* (httpcontext, etc.) objeto para armazenar a sessão. Além disso, o uso das funções Application_BeginRequest/Application_endRequest é complicado, pois elas são demitidas para cada solicitação HTTP (arquivos ASPX, arquivos CSS, arquivos JS etc.), quando eu quero apenas instanciar uma sessão uma vez por solicitação.

A preocupação que tenho é que não quero que meus pontos de vista ou controladores tenham acesso a sessões de Nibernate (ou, de maneira mais geral, Nibernate namespaces e Code). Isso significa que eu não quero lidar com sessões no nível do controlador nem na visualização.

Tenho algumas opções em mente. Qual deles parece o melhor?

  • Use interceptores (como em Grails) que são acionados antes e depois da ação do controlador. Estes abririam e fechariam sessões/transações. Isso é possível no mundo do ASP.NET MVC?
  • Use o CurrentSessionContext Singleton fornecido pelo Nibernate em um contexto da Web. Usando esta página Como exemplo, acho que isso é bastante promissor, mas isso ainda requer filtros no nível do controlador.
  • Use o httpcontext.current.items para armazenar a sessão de solicitação. Isso, juntamente com algumas linhas de código no global.asax.cs, pode facilmente me fornecer uma sessão no nível de solicitação. No entanto, isso significa que as dependências serão injetadas entre o Nibernate e meus pontos de vista (httpContext).

Muito obrigado!

Foi útil?

Solução

Bem, pessoal, depois de alguns dias de trabalho, finalmente decidi usar o httpcontext.current.items para carregar a sessão.

Funciona muito bem!

Veja como eu fiz isso

import System.Web
class SessionManager {
    public static ISession GetSession()
        var session = HttpContext.Current.Items["NHibernateSession"];
        if (session == null) {
            session = ...; // Create session, like SessionFactory.createSession()...
            HttpContext.Current.Items.Add("NHibernateSession", session);
        }
        return session;
    }

    public static void CloseSession()
    {
        var session = HttpContext.Current.Items["NHibernateSession"];
        if (session != null) {
            if (session.IsOpen) {
                session.close();
            }
            HttpContext.Current.Items.Remove("NHibernateSession");
        }
    }
}

Usando os métodos estáticos fornecidos por esta classe, é possível obter uma sessão (por exemplo, em um controlador) vinculado ao HTTPContext atual (a solicitação da web atual). Precisamos de outro trecho de código para ligar para o método CloseSession () quando a solicitação for concluída.

Em global.asax.cs:

protected void Application_EndRequest(object sender, EventArgs args)
{
    NHibernateSessionManager.CloseSession();
}

O evento Application_endRequest é chamado automaticamente quando a sessão é concluída, para que a sessão possa ser fechada corretamente e descartadas. Isso é útil, porque, caso contrário, teríamos que fazer isso em todos os controladores!

Outras dicas

Use DI junto com um COI. A maioria dos COI vinha com um comportamento de instanciação por solicitação.

Minha "solução" envolve o uso da unidade para injetar sessão por solicitação nos controladores:

http://letsfollowtheyellowbrickroad.blogspot.com/2010/05/nhibernate-sessions-in-aspnet-mvc.html

Dar uma olhada em S#Arquitetura ARP. É uma arquitetura muito boa para asp.net MVC e Nibernate.

Você pode adicionar um filtro de ação que pode gerenciar suas sessões e transações Nibernato. (Isso pode ser feito no nível de ação ou controlador.) Aqui está um exemplo disso:

http://weblogs.asp.net/srkirkland/archive/2009/09/03/asp-nalt-mvc-ransaction-attribute-using-nhibernate.aspx

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