A terminologia da pergunta realmente não corresponde ao código de exemplo. O Ambient Context
é um padrão usado para capturar uma dependência de qualquer classe em qualquer módulo o mais fácil possível, sem poluir todas as classes para aceitar a interface da dependência, mas ainda mantendo a idéia de inversão de controle. Tais dependências geralmente são dedicadas ao registro, segurança, gerenciamento de sessões, transações, armazenamento em cache, auditoria, para qualquer preocupação transversal nesse aplicativo. É de alguma forma irritante para adicionar um ILogging
, ISecurity
, ITimeProvider
para construtores e na maioria das vezes nem todas as classes precisam tudo ao mesmo tempo, então eu entendo a sua necessidade.
E se o tempo de vida da ISession
instância for diferente ILogger
daquele? Talvez a instância ISession deva ser criada em cada solicitação e no ILogger uma vez. Portanto, ter todas essas dependências governadas por um objeto que não é o próprio contêiner não parece a escolha certa, devido a todos esses problemas com gerenciamento e localização de vida útil e outros descritos neste encadeamento.
A IAmbientContext
questão não resolve o problema de não poluir todos os construtores. Você ainda precisa usá-lo na assinatura do construtor, com certeza, apenas uma vez dessa vez.
Portanto, a maneira mais fácil NÃO é usar a injeção de construtor ou qualquer outro mecanismo de injeção para lidar com dependências transversais, mas usando uma chamada estática . Na verdade, vemos esse padrão com bastante frequência, implementado pela própria estrutura. Verifique Thread.CurrentPrincipal, que é uma propriedade estática que retorna uma implementação da IPrincipal
interface. Também é configurável para que você possa alterar a implementação, se assim o desejar, para que não esteja acoplado a ela.
MyCore
parece agora algo como
public class MyCoreClass
{
public void BusinessFeature(string data)
{
LoggerContext.Current.Log(data);
_repository.SaveProcessedData();
SessionContext.Current.SetData(data);
...etc
}
}
Esse padrão e possíveis implementações foram descritos em detalhes por Mark Seemann neste artigo . Pode haver implementações que dependem do próprio contêiner de IoC que você usa.
Você deseja evitar AmbientContext.Current.Logger
, AmbientContext.Current.Session
pelas mesmas razões descritas acima.
Mas você tem outras opções para resolver esse problema: use decoradores, interceptação dinâmica se o seu contêiner tiver esse recurso ou AOP. O contexto ambiental deve ser o último recurso, pois seus clientes ocultam suas dependências por meio dele. Eu ainda usaria o Contexto ambiente se a interface realmente imitar meu impulso de usar uma dependência estática como DateTime.Now
ou ConfigurationManager.AppSettings
e essa necessidade aumentar com bastante frequência. Mas, no final, a injeção do construtor pode não ser uma má idéia para obter essas dependências onipresentes.
IService
usado para se comunicar com outros serviços?" SeIService
representa uma dependência vaga de outros serviços, parece um localizador de serviço e não deveria existir. Sua classe deve depender de interfaces que descrevam explicitamente o que o consumidor fará com eles. Nenhuma classe precisa de um serviço para fornecer acesso a um serviço. Uma classe precisa de uma dependência que faça algo específico que a classe precisa.