【问题标题】:how to resolve assembly dependency in dotnet core?如何解决dotnet核心中的程序集依赖?
【发布时间】:2021-09-14 08:52:47
【问题描述】:

我有多个项目如下:

1- 基础设施:这是 classLibrary 项目,包含基础设施类、接口等。

2- Runable Project:这是asp.net core 5项目,用于启动其他业务项目,参考Infrastructure项目

3- 业务解决方案:这有多个用于api, service, domain, ... 层的类库项目

Infrastructure项目中有如下界面:

using Microsoft.Extensions.DependencyInjection;


namespace Infrastructure
{
public interface IModuleLoader
{
     void Register(IServiceCollection serviceCollection);
}
}

Business.Api 项目中有一个实现IModuleLoader 接口的类

namespace Business.Api
{
public class BusinessModuleLoader : IModuleLoader
{
    public void Register(IServiceCollection services)
    {
        services.AddControllers().AddApplicationPart(this.GetType().Assembly);
//...
    }
}
}

Runable项目中有这个类用于加载业务Assembly项目

public static class ModuleLoaderHelper
{
    public static void LoadModules(this IServiceCollection services)
    {
        AutoLoading(services);
    }

    private static void AutoLoading(IServiceCollection services)
    {
        var path = AppDomain.CurrentDomain.BaseDirectory;
        DirectoryInfo di = new DirectoryInfo(path);
        FileInfo[] fis = di.GetFiles("Business.Api.dll");

        var mtype = typeof(Infrastructure.IModuleLoader);

        foreach (var f in fis)
        {
            try
            {

                var loadContext = new PluginLoadContext(f.FullName);
                var asm = loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(f.FullName)));
                         var moduleLoader = asm.GetTypes().FirstOrDefault(p => mtype.IsAssignableFrom(p));

                if (moduleLoader == null)
                    continue;

                Infrastructure.IModuleLoader loader = (Infrastructure.IModuleLoader)Activator.CreateInstance(moduleLoader);

                loader.Register(services);

            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message + exp.StackTrace);
            }
        }
    }

    class PluginLoadContext : AssemblyLoadContext
    {
        private AssemblyDependencyResolver _resolver;

        public PluginLoadContext(string pluginPath)
        {
            _resolver = new AssemblyDependencyResolver(pluginPath);
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
            if (assemblyPath != null)
            {
                return LoadFromAssemblyPath(assemblyPath);
            }

            return null;
        }

        protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
        {
            string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
            if (libraryPath != null)
            {
                return LoadUnmanagedDllFromPath(libraryPath);
            }

            return IntPtr.Zero;
        }
    }
}
}

已加载的Business.Api 程序集和BusinessModuleLoader 类型存在于已加载的程序集中,但是
在这行代码中不匹配 var moduleLoader = asm.GetTypes().FirstOrDefault(p => mtype.IsAssignableFrom(p)); 和变量 moduleLoadernull

我该如何解决这个问题?

【问题讨论】:

  • 不应该di.GetFiles("Business.Api.dll"); 更像di.GetFiles("Business.*.dll"); ???你也不应该使用loadContext.Load 而不是loadContext.LoadFromAssemblyName
  • @Stamos 此行用于模式匹配过滤器搜索程序集di.GetFiles("Business.*.dll");

标签: c# asp.net-web-api .net-core .net-assembly


【解决方案1】:

您可以尝试先加载所有程序集,然后循环注册

private static void AutoLoading(IServiceCollection services)
        {
            var path = AppDomain.CurrentDomain.BaseDirectory;
            DirectoryInfo di = new DirectoryInfo(path);
            FileInfo[] fis = di.GetFiles("Business.*.dll");

            var mtype = typeof(Infrastructure.IModuleLoader);

            foreach (var f in fis)
            {
                try
                {
                    var res = AppDomain.CurrentDomain.GetAssemblies().Any(loadedAssembly => AssemblyName.ReferenceMatchesDefinition(loadedAssembly.GetName(), AssemblyName.GetAssemblyName(f)));
                    if (!res)
                    {
                        AppDomain.CurrentDomain.Load(Assembly.LoadFrom(f).GetName());
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.Message + exp.StackTrace);
                }

            }

            try
            {
                _modules = AppDomain.CurrentDomain.GetAssemblies().Where(assembly => assembly.FullName!.StartsWith("Business.*.dll"))
                    .SelectMany(assembly => assembly.GetTypes()).Where(type =>
                    {
                        if (type.IsClass && !type.IsAbstract)
                        {
                            bool isAssignable = typeof(Infrastructure.IModuleLoader).IsAssignableFrom(type);

                            return isAssignable;
                        }
                        return false;
                    }).ToList()
                    .Select(Activator.CreateInstance).Cast<Infrastructure.IModuleLoader>().ToList();

            
                foreach (var module in _modules)
                {
                    module.Register(services);
                }
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message + exp.StackTrace);
            }
        }

【讨论】:

  • 你好亲爱的,这段代码抛出异常无法加载文件或程序集
  • dotnet 运行时不加载程序集依赖项,我们应该使用 AssemblyDependencyResolver 加载它们,我使用它并加载所有依赖项,但我认为我的程序集加载在不同的上下文、线程或类似的东西中这会导致 Infrastructure.IModuleLoaderBusinessModuleLoader 不匹配
  • @MohsenSaleh 错误应该与di.GetFiles("Business."); 有关,它应该是di.GetFiles("Business.*.dll");。我没有使用AssemblyDependencyResolver,我不知道它在哪个域加载程序集。如您所见,我在CurrentDomain 中加载程序集。这对我来说非常有用。我还实现了使用顺序和依赖关系的逻辑。
猜你喜欢
  • 1970-01-01
  • 2019-03-12
  • 2018-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多