Autofac передача параметра во вложенные типы - PullRequest
7 голосов
/ 21 апреля 2011

Я использую Autofac в качестве IoC в своем сервисе WCF. У меня есть ситуация, когда я хочу передать объект вложенному типу (то есть типу, который не разрешен напрямую, но при разрешении другого типа). Насколько я понял, передача этого объекта в качестве параметра конструктора является предпочтительным способом в Autofac. Вот пример такой ситуации.

Вложенный тип:

public class EventLogger<T> : IEventLogger<T>
{
    public EventLogger(IRepository<T> repository, User currentUser) { ... }  
}

Тип, который я на самом деле пытаюсь определить:

public class SomeBusinessObject  
{  
    public SomeBusinessObject(IEventLogger<SomeLogEventType> logger, ...) { ... }  
}

Регистрация:

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
builder.RegisterGeneric(typeof(EventLogger<>)).As(typeof(IEventLogger<>));
builder.RegisterType<SomeBusinessObject>();

Разрешение внутри моей службы WCF:

var currentUser = GetUserFromServiceContext();  
var bo = lifetimeScope.Resolve<SomeBusinessObject>();

Как и где мне передать текущего пользователя моему логгеру? Должен ли я предполагать, что операция WCF должна знать, что для разрешения SomeBusinessObject необходимо сначала разрешить IEventLogger и передать разрешенный экземпляр при разрешении SomeBusinessObject? Как то так (простите, если это не работает, это просто идея):

var currentUser = GetUserFromServiceContext();  
var logger = lifetimeScope.Resolve<IEventLogger<SomeLogEventType>>(new NamedParameter("currentUser", currentUser));  
var bo = lifetimeScope.Resolve<SomeBusinessObject>(new NamedParameter("logger", logger));

Если это решение, что произойдет, если тип будет вложен глубже? Разве это не разрушает хотя бы какую-то цель внедрения зависимости?

1 Ответ

6 голосов
/ 21 апреля 2011

ИМХО, я думаю, что вы нарушаете один из принципов МОК в том, что компонент не должен знать о зависимостях его зависимостей. В вашем случае контейнер не знает, что SomeBusinessObject зависит от User.

При этом вы можете использовать Делегатские заводы Autofac . Вы можете вручную зарегистрировать Func<User, SomeBusinessObject>, чтобы скрыть детали цепочки зависимостей из кода клиента:

var builder = new ContainerBuilder();
builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>));
builder.RegisterGeneric(typeof(EventLogger<>)).As(typeof(IEventLogger<>));
builder.RegisterType<SomeBusinessObject>();

builder.Register<Func<User, SomeBusinessObject>>(c => {
    // Autofac should be able to resolve these Func<> automatically:
    var loggerFactory = c.Resolve<Func<User, IEventLogger<SomeLogEventType>>>();
    var sboFactory = c.Resolve<Func<IEventLogger<SomeLogEventType>, SomeBusinessObject>>();

        // Now we can chain the Funcs:
    return u => sboFactory(loggerFactory(u));
});

Теперь в своем коде клиента вы можете сделать:

var currentUser = GetUserFromServiceContext();  
var sboFactory = lifetimeScope.Resolve<Func<User, SomeBusinessObject>>();
var bo = sboFactory(currentUser);

Кроме того, я думаю, что поддержка lamba / Func делает Autofac лучшим контейнером IOC. Вы можете делать сумасшедшие мощные вещи, если знаете, как сочинять Funcs.

...