Autofac passing parameter to nested types

心不动则不痛 提交于 2020-01-11 04:59:04

问题


I am using Autofac as my IoC in my WCF service. I have a situation where I want to pass an object to a nested type (ie a type that is not resolved directly, but when resolving another type). As far as I understood, passing this object as a constructor parameter is the preferred way in Autofac. Here is an example of such a situation.

The nested type:

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

The type I am actually trying to resolve:

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

The registration:

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

The resolving inside my WCF service operation:

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

How and where should I pass the current user to my logger? Should I assume that the WCF operation has to know that resolving SomeBusinessObject requires to resolve IEventLogger first and pass a resolved instance when resolving SomeBusinessObject? Something like this (pardon me if this does not work, it is just an idea):

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

If this is the solution, what happens if the type is nested deeper? Doesn't that defeat at least some of the purpose of dependency injection?


回答1:


IMHO, I think you're violating one of the principles of IOC in that a component should not need to know about the dependencies of it's dependencies. In your case, the container doesn't know that SomeBusinessObject has a dependency on User.

That being said, you may be able to leverage Autofac's Delegate Factories. You could manually register a Func<User, SomeBusinessObject> to hide the dependency chain details from the client code:

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));
});

Now in your client code, you can do:

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

As an aside, I think the lamba/Func support is what makes Autofac the best IOC container. You can do some crazy powerful things if you know how to compose Funcs.



来源:https://stackoverflow.com/questions/5741761/autofac-passing-parameter-to-nested-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!