【问题标题】:Autofac resolve in deep layerAutofac在深层解析
【发布时间】:2016-04-26 18:28:15
【问题描述】:

我很难在我的应用程序中集成 autofac..

我的应用程序与其他应用程序集成,当与另一个应用程序的连接由合适的“协议”对象维护时

// This class is inherited by a few other classes
public abstract class Protocol

我有一个层由它自己的线程运行并处理连接请求。对于每种类型的请求,都会创建不同类型的协议(不同的协议对象)

// For example lets say every protocol (Inhertiance of Protocol abstract object) 
// takes in ctor these 3 services + runtime configuration object:
public Protocol1(IFramingAgent, IFramingAlgorithm, IFramingParser, configObject configuration)

我的协议对象被键控注册为协议。还, 每个服务都使用密钥注册,因为每个协议使用从同一接口继承的不同类型。当然,所有这些都注册为 PerDependency (虽然我不是很了解这个 lifeCycle 与 PerScope 的区别,非常感谢解释)

这是我糟糕的课程:

public class ProtocolsLayer : Layer
{
    private IFrameworkDependencyResolver _resolver;
    private IConfigurationService _configService;

    public ProtocolsLayer(IFrameworkDependencyResolver resolver, IConfigurationService configurationService)
    {
        _resolver = resolver;
        _configService = configurationService;
    }

    void HandleConnection1()
    {
        // What I have at the moment (terrible):

        // Resolve the fitting services (All keyed - key is received by the type, Resolve and ResolveWithParameters used here are my wrappers)
        var agent = _resolver.Resolve<IFramingAgent>(typeof(Protocol1FramingAgent));

        var algo = _resolver.Resolve<IFramingAlgorithm>(typeof(Protocol1FramingAlgorith));

        var parser = _resolver.Resolve<IFramingParser>(typeof(Protocol1FramingParser));

        // A parameter I get and pass to each protocol at runtime
        var protocolConfig = _configService.GetConfig<Protocol1Configuration>();

        // Finally resolve the protocol with it's parameters:

        protocol = _resolver.ResolveWithParameters<IProtocol>(typeof(Protocol1), new List<object>{
            agent, resolver, parser, protocolConfig 
        });

        //...

        // Theres gotta be a better way!! 
    }

    void HandleConntection2()
    {
        // Same as in protocol1
    }

    void HandleConnection3()
    {
        // Same as in protocol1
    }
}

请记住,我不希望引用 autofac,这意味着我不能使用我听到的 IIndex。

谢谢!

【问题讨论】:

    标签: c# dependency-injection autofac resolve


    【解决方案1】:

    您应该让依赖注入框架管理实例化。

    您使用ResolveWithParameter 方法,其中这些参数已由依赖注入框架解析。这不是必需的,您可以让框架为您找到依赖项:

    如果Protocol1 需要一个命名参数,您可以在注册过程中指定它。

    builder.Register(c => c.Resolve<IConfigurationService>()
                           .GetConfig<Protocol1Configuration>())
           .As<Protocol1Configuration>(); 
    
    builder.RegisterType<Protocol1>()
           .Named<IProtocol1>(nameof(Protocol1))
           .WithParameter((pi, c) => pi.ParameterType == typeof(IFramingAgent), 
                          (pi, c) => c.ResolveNamed<IFramingAgent>(nameof(Protocol1))
           .WithParameter((pi, c) => pi.ParameterType == typeof(IFramingAlgorithm), 
                          (pi, c) => c.ResolveNamed<IFramingAlgorithm>(nameof(Protocol1));
    builder.RegisterType<FramingAgentProtocol1>()
           .Named<IFramingAgent>(nameof(Protocol1));
    builder.RegisterType<FramingAlgorithmProtocol1>()
           .Named<IFramingAlgorithm>(nameof(Protocol1));
    

    那么ProtocolsLayer只需要依赖IIndex&lt;String, Func&lt;IProtocol&gt;&gt;(或Func&lt;Owned&lt;Protocol1&gt;&gt;

    public class ProtocolsLayer 
    {
        public ProtocolsLayer(IIndex<String, Func<IProtocol>> index)
        {
            this._index = index; 
        }
    
        private readonly IIndex<String, Func<IProtocol>> _index;
    
        public void HandleConnection1()
        {
            IProtocol protocol = this._index[nameof(Protocol1)](); 
        }
    }
    

    如果您不想为整个应用程序引入对IIndex&lt;,&gt; 的依赖,您可以引入将在您的运行时定义的IProtocolFactory,并仅为注册项目创建实现。

    在您的运行时项目中:

    public interface IProtocolFactory
    {
        IProtocol Create(String protocolName)
    }
    

    在您的注册项目中:

    public class ProtocolFactory : IProtocolFactory
    {
    
        public ProtocolFactory(IIndex<String, IProtocol> index)
        {
            this._index = index; 
        }
    
        private readonly IIndex<String, IProtocol> _index; 
    
        public IProtocol Create(String protocolName)
        {
            return this._index[typeof(TProtocol).Name]; 
        }
    }    
    

    那么你的ProtocolsLayer 类将如下所示:

    public class ProtocolsLayer 
    {
        public ProtocolsLayer(IProtocolFactory protocolFactory)
        {
            this._protocolFactory = protocolFactory; 
        }
    
        private readonly IProtocolFactory _protocolFactory;
    
        public void HandleConnection1()
        {
            IProtocol protocol = this._protocolFactory.Create("Protocol1"); 
        }
    }
    

    您也可以注册一个Func&lt;String, IProtocol&gt;,其名称为resolve IProtocol

    ProtocolsLayer 看起来像这样:

    public class ProtocolsLayer 
    {
        public ProtocolsLayer(Func<String, IProtocol> protocolFactory)
        {
            this._protocolFactory = protocolFactory; 
        }
    
        private readonly Func<String, IProtocol> _protocolFactory;
    
        public void HandleConnection1()
        {
            IProtocol protocol = this._protocolFactory("Protocol1"); 
        }
    }
    

    和这样的注册:

    builder.Register(c => (String namedProtocol) => c.ResolveNamed<IProtocol>(namedProtocol)
           .As<Func<String, IProtocol>>(); 
    

    但我不会推荐这种解决方案,因为 Func&lt;String, IProtocol&gt; protocolFactory 依赖的意图并不明确。拥有IProtocolFactory 接口使依赖目标易于理解。

    【讨论】:

    • 西里尔谢谢!您能否更详细地解释一下这个 IProtocolsFactory 的外观?这听起来对我来说是理想的解决方案
    • @S.Peter 我编辑了我的帖子以包含一个IProtocolFactory 示例
    • 我怎么能使用它而不是暴露给 IIndex
    • IIndex&lt;&gt; 没有暴露,只有引用Autofac的项目知道
    • 哦,我明白了,另一个问题是我如何在没有名字的情况下做到这一点?因为以后可能会更改名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多