Design, Arquitetura, Problema com requisitos e acoplamento
28/09/2012
0
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
Posts
01/10/2012
Washington Morais
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.
01/10/2012
Vitor Rubio
02/10/2012
Washington Morais
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
02/10/2012
Vitor Rubio
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?
02/10/2012
Washington Morais
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
02/10/2012
Vitor Rubio
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?
Clique aqui para fazer login e interagir na Comunidade :)