如何解决dotnet核心中的程序集依赖性?

时间:2021-07-02 11:38:18

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

我有多个项目如下:

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项目中有这个类用于加载业务组装项目

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

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

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

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