Design, Arquitetura, Problema com requisitos e acoplamento

28/09/2012

0

Estou fazendo uma aplicação .net usando nHibernate para a persistência, mas criando repositórios, assim o uso do hibernate é transparente para as classes que usam o repositório.
No meu código eu separei as classes de negócio, de repositório, de aplicação e de apresentação (não está muito bem separado, mas estou aprendendo)
Tenho uma classe de negócio de Log, que usa um repositório de log para gravar no banco de dados um log de qualquer operação CRUD.
Como qualquer operação CRUD é logada, coloquei o "uso" ou chamada dessa classe de log na base do repositório. No entanto não me parece o melhor lugar para colocar isso, por dois motivos:
1) Eu preciso logar o usuário que fez as alterações CRUD, então eu passo uma instância de um objeto usuario para obter seu nome ou id.
2) Eu preciso de informações do browser, ip, informações da sessão e assim por diante, por isso insiro um objeto Sessao, que contém internamente um HTTPContext

Com isso eu crio um forte acoplamento do repositório com as classes sessão e usuário, e com o HTTPContext. Isso me impede de usar minhas classes de negócio e de repositório em uma aplicação windowsforms.

Sei que essa não é a melhor forma de fazer isso, gostaria de sugestões de melhoria. Não sei se devo retirar o log da camada de repositório e passar para a camada de aplicação ou se deveria usar injeção de dependência. Qum poderia me dar um exemplo de DI?

Abaixo uma amostra do meu código

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using LiderTel.Modelo;

namespace LiderTel.Persistencia
{
public class BaseRepositorio<T> where T: Entity
{
private Sessao _sessaoInjetadaRepositorio;
private Usuario _usuarIoinjetadoRepositorio;

protected virtual Sessao GetSessaoInjetadaRepositorio()
{
return _sessaoInjetadaRepositorio;
}

protected virtual Usuario GetUsuarioInjetadoRepositorio()
{
return _usuarIoinjetadoRepositorio;
}

public BaseRepositorio(Sessao sess, Usuario usu)
{
_sessaoInjetadaRepositorio = sess;
_usuarIoinjetadoRepositorio = usu;
}

public BaseRepositorio(Sessao sess)
: this(sess, sess==null?null:sess.UsuarioCriador)
{

}

public BaseRepositorio()
: this(SessionServices.GetSessaoCorrente(), SessionServices.GetSessaoCorrente()==null?null:SessionServices.GetSessaoCorrente().UsuarioCriador)
{

}


private string RetornaIdUsuario()
{
return (GetUsuarioInjetadoRepositorio() != null) ? GetUsuarioInjetadoRepositorio().ID.ToString() : "";
}

public virtual void Add(T ent)
{
ent.Criacao = DateTime.Now;
ent.UsuarioCriador = GetUsuarioInjetadoRepositorio();
ent.Excluido = false;
ent.Ativo = true;
NHibernateHelper.GetDefaultSession().Save(ent);



Log log = new Log();
log.Acao = string.Format(" criado por .", ent.GetType().Name, ent.ID.ToString(), RetornaIdUsuario());
log.TipoEvento = TipoEventoLog.Inclusao;
log.Entidade = ent.ID;
if (GetSessaoInjetadaRepositorio() != null)
{
log.SessaoID = GetSessaoInjetadaRepositorio().ID;
}
log.ComoEstava = ent.InternalToString();

LogRepository logrep = new LogRepository(GetSessaoInjetadaRepositorio(), GetUsuarioInjetadoRepositorio());
logrep.Add(log);
}
}
}
Vitor Rubio

Vitor Rubio

Responder

Posts

01/10/2012

Washington Morais

Olá Vitor.

Uma sugestão seria voce utilizar uma camada de Services que seria responsável pela comunicação entre sua camada UI e a de negócios. Crie um objeto de modelo especifico com as informações que voce precisa e trafegue este objeto entre as camadas através do serviço.

Com isso, é possivel reutilizar os metodos entre diferentes aplicações.

Abraço.

Responder

01/10/2012

Vitor Rubio

Já estou criando essa camada. O problema é que, como eu disse, a minha necessidade de log (e armazenar ip do browser, ip do servidor etc) cria um acoplamento entre minhas classes de negócio e a classe HTTPContext do .net, e um acoplamento entre o repositório e a classe de log, o que impossibilita que eu aproveite essa camada de negócios em um ambiente windowsforms.
Responder

02/10/2012

Washington Morais

Bom, não sei se estou viajando ou não entendi direito, mas a ideia é justamente criar uma classe de negócio onde estas informações são passadas desde a UI até a classe de LOG.

O fato de voce precisar destas informações especificas do browser, "te obriga" a recuperar estas informações na camada de UI ou utilizar o objeto Session do HttpContext em outras camadas, o que acaba não sendo uma boa pratica.

Uma outra possibilidade é que seu metodo no serviço espere como entrada um XML ( o padrão voce pode definir ) e todos que implementarem sua interface do serviço terão que te enviar este XML com as informações que o seu LOG precisa.

Com isso, qualquer liguagem que faça uso de XML poderá consumir seu serviço, independente de ser uma aplicação Web ou não.

Abraços

___________________
Washington Morais
MCP / MCTS
Responder

02/10/2012

Vitor Rubio

Minha aplicação não é baseada em webservices. O meu problema não é bem o acoplamento entre o log e o HTTPContext, porque esse acoplamento eu posso resolver criando uma interface chamada ISessao, e criando duas classes que implementem essa interface: uma SessaoWeb e uma SessaoDesktop, assim eu posso passar um isessao para o log, sendo este ou um SessaoWeb ou um SessaoDesktop, dependendo da plataforma. Posso fazer com que os métodos da interface sejam os métodos que me retornem o usuário, host, etc. Dá para usar o objeto request na web e as classes para lidar com usuário no desktop.

O problema é mais sutil: Todas as classes do meu repositório estão acopladas ou com o Log ou com essa ISessao. Para cada classe do repositório eu tenho um constructor onde eu passo o ISessao. A classe ancestral do meu rep. usa esse objeto passado pelo constructor para fazer os logs de operações CRUD.

Não sei se está certo isso, de passar um isessao para os repositórios, ou se eu deveria tirar de dentro do repositório essa operação de log. O que você acha?
Responder

02/10/2012

Washington Morais

Por padrão, quanto menos acoplado melhor :).

A idéia de utilizar WCF é justamente para que as regras de sua aplicação possam ser consumidas por qualquer front-end. De qualquer forma, voce ainda pode usar o XML como entrada de dados. Com isso, suas classes não precisam ir trafegando objetos de sessão.


Abraços

___________________
Washington Morais
MCP / MCTS
Responder

02/10/2012

Vitor Rubio

Ok, esqueça o objeto Session do ,net framework. Qaundo eu disse Sessão estava me referindo a minha classe de sessão, que é algo mais ou menos assim:

interface Isessao
{
Usuario GetUsuario();
string GetNomeComputador();
string GetIP();
}

suponha que eu faça via WCF ou SOAP webservices. A questão não é acoplamento entre UI e camada de aplicação, ou acoplamento entre camada de aplicação e objetos de negócio.

O problema é mais abaixo: eu acoplei os repositórios com o Log, pois todas as operações no repositório são logadas. Como efeito colateral, como log precisa de um isessao, eu tenho que passar o Isessao no construtor do repositorio. ou seja: repositorio -->depende de log --> depende de isessao.

Como reduzo essa dependência? É correto usar o log dentro do repositório ou eu teria que criar mais uma camada?
Responder

Assista grátis a nossa aula inaugural

Assitir aula

Saiba por que programar é uma questão de
sobrevivência e como aprender sem riscos

Assistir agora

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar