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, ITimeProviderpara 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 ISessioninstância for diferente ILoggerdaquele? 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 IAmbientContextquestã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 IPrincipalinterface. 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.Sessionpelas 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.Nowou ConfigurationManager.AppSettingse 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.
IServiceusado para se comunicar com outros serviços?" SeIServicerepresenta 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.