【问题标题】:Autofac passing parameter to nested typesAutofac将参数传递给嵌套类型
【发布时间】:2011-08-10 03:36:29
【问题描述】:

我在 WCF 服务中使用 Autofac 作为我的 IoC。我有一种情况,我想将一个对象传递给一个嵌套类型(即一种不直接解析的类型,但是在解析另一种类型时)。据我了解,将此对象作为构造函数参数传递是 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));

如果这是解决方案,如果类型嵌套更深会发生什么?这是否至少破坏了依赖注入的某些目的?

【问题讨论】:

    标签: c# ioc-container autofac


    【解决方案1】:

    恕我直言,我认为您违反了 IOC 的一项原则,即组件不需要了解其依赖项的依赖项。在您的情况下,容器不知道 SomeBusinessObject 依赖于 User

    话虽如此,您也许可以利用 Autofac 的 Delegate Factories。您可以手动注册 Func&lt;User, SomeBusinessObject&gt; 以隐藏客户端代码中的依赖链详细信息:

    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,你可以做一些疯狂而强大的事情。

    【讨论】:

    • 感谢您的回答。你能详细说明我违反了国际奥委会的原则吗?我同意你的看法,我的最后一个解决方案是,但我不知道为什么你的答案也不会。我的意思是,您的回答还表明,要构建 SomeBusinessObject,您需要知道它需要一个用户。
    • 我的回答也是。 :) 这是一种解决方法。但是如果我必须按照设计使用对象,我会这样做至少尽可能地封装依赖关系。
    • 好的,那我明白了! :-) 如果您必须更改对象的设计? ;-) 我对 IoC 真的很陌生,但我还没有真正理解它......
    • 你可以考虑是否有注册类型User的方法。我用IPrincipal 做类似的事情builder.Register(c =&gt; HttpContext.Current.User);
    • 我明白了。这意味着每次我有一个User作为参数时,都会这样解析?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多