首页 > 解决方案 > 来自 Assembly 的 Autofac 寄存器类型

问题描述

我在我的解决方案中使用 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;
                }
            });

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

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

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

截屏

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

标签: c#.netautofac

解决方案


经过一段时间的真正挖掘,我将文件加载简化为:

        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 ehh)

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


推荐阅读