【问题标题】:Autofac register types from Assembly来自 Assembly 的 Autofac 寄存器类型
【发布时间】:2018-08-09 21:52:48
【问题描述】:

我在我的解决方案中使用 autofac 来解决不同项目之间的库依赖关系。这个想法是在某种意义上制作热插拔库,只有少数几个核心库是应用程序所依赖的,它们的前缀是"vmecore.*.dll"。必须在任何其他库之前向 autofac 注册。

任何其他以“vme.*.dll”为前缀的库都已加载,然后我寻找实现“IVmeExtension”的第一个类型——它定义了一个Initiate()方法——我注册,激活,最后初始化。

注册核心库的代码:

        Directory.GetFiles(path, "vmecore.*.dll")
            .Select(Assembly.LoadFile)
            .ToList()
            .ForEach(ass =>
            {
                //var validAss = Assembly.Load(ass.FullName);

                builder.RegisterAssemblyTypes(ass)
                    .Where(t => t.IsAssignableTo<IVmeExtension>())
                    .SingleInstance();
                //return;

                // Iterate through all the types in the assembly
                foreach (var type in ass.GetExportedTypes()
                        .Where(a => a.IsClass &&
                                    !a.IsAbstract &&
                                    a.Namespace != null &&
                                    a.Namespace.Contains(@"VME")))
                {
                    // Get the first type of IVmeExtension
                    if (!typeof(IVmeExtension).IsAssignableFrom(type)) continue;

                    //builder.RegisterType(type).SingleInstance();
                    coreExtension.Add(type);
                    break;
                }
            });

下面的 sn-p 是容器构建时调用的回调委托。核心库需要在热插拔扩展之前解析和初始化,因为大多数扩展都依赖于它们。

           //Register a call back when container is built so we can resolve core extensions first
            builder.RegisterBuildCallback(container =>
            {
                coreExtension.ForEach(ext =>
                {
                    try
                    {
                        var inst = (IVmeExtension)container.Resolve(ext);
                        inst.Initiate();

                        Interface.LogInfo($"VME: Core extension '{inst.Name}'");
                    }
                    catch (Exception e)
                    {
                        // we log the error here.
                        throw;
                    }
                });
            });

解析的第二个扩展需要将前者注入构造函数——对于这个实验,我在构造函数中手动解析它以查看注册的服务——。问题出现在这里;我收到异常“请求的服务'..'尚未注册”但查看注册类型是文学那里。

Screenshot

我已经尝试过在这篇帖子https://github.com/autofac/Autofac/issues/593 上建议的解决方案,但是当我这样做时,我得到一个系统指针异常,并且它非常清楚,因为当进入实例(var inst = (IVmeExtension)container.Resolve(ext)) 的激活时,IDE 实际上正在带我到一个完全不同的类的构造函数 - 不同的类在执行程序集中 -

【问题讨论】:

  • 那些扩展可能应该从构造函数初始化(如果有的话,需要它们的依赖项)——你有什么理由必须通过额外的初始化调用使它成为一个特殊情况?另外 - RegisterAssemblyTypes 确保它只是具体的类 - 所以不应该有理由检查抽象等。 ToList也似乎是多余的。你能提供一个MVCE吗?

标签: c# .net autofac


【解决方案1】:

经过一段时间的深入研究,我将文件加载简化为:

        var path = "C:\\rust server\\RustDedicated_Data\\Managed";
        var coreFiles = Directory.GetFiles(path, "vmecore.*.dll");

        var coreExtension = new List<Type>();
        // Load each assembly into domain
        foreach (var file in coreFiles)
        {
            var lAssembly = Assembly.LoadFile(file);
            var assembly = Assembly.Load(lAssembly.FullName);

            builder.RegisterAssemblyTypes(assembly)
                .Where(t => t.IsAssignableTo<IVmeExtension>())
                .SingleInstance();

            // Add all IVmeExtension types
            coreExtension.AddRange(assembly.GetExportedTypes()
                .Where(a => a.IsClass &&
                            !a.IsAbstract &&
                            a.Namespace != null &&
                            a.Namespace.Contains(@"VME") &&
                            typeof(IVmeExtension).IsAssignableFrom(a)));
        }

我的原始版本无法正常工作的原因是,即使加载了文件程序集,它也没有加载到应用程序域中,所以当我注册一个类型时,它会得到一个哈希码——autofac 使用它——。当应用程序尝试解析类型时,它会将程序集加载到应用程序域中。此时,所有新加载的类型都有不同的哈希码——我认为这是正在发生的事情——导致我描述的错误。

奇怪的是,我提到的无效指针异常实际上是在激活第二个扩展并解决其依赖关系时产生的 - 以正确的方式 - 其中一个打开了一个 tcp 套接字,该套接字具有错误输入的 ip 地址(uurghh co-workers嗯)

有时,更简单的代码是更好的代码:)

【讨论】:

    猜你喜欢
    • 2015-01-06
    • 2016-07-02
    • 2017-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    相关资源
    最近更新 更多