C# 如何在dotnetcore中动态加载程序集
我正在构建一个web应用程序,在这里我需要单独的关注点,即在不同的项目中进行抽象和实现 为了实现这一点,我尝试实现一个compositionroot概念,其中所有实现都必须有一个C# 如何在dotnetcore中动态加载程序集,c#,asp.net-core,.net-core,C#,Asp.net Core,.net Core,我正在构建一个web应用程序,在这里我需要单独的关注点,即在不同的项目中进行抽象和实现 为了实现这一点,我尝试实现一个compositionroot概念,其中所有实现都必须有一个ICompositionRootComposer实例来注册服务、类型等 public interface ICompositionRootComposer { void Compose(ICompositionConfigurator configurator); } 在构建层次结构中直接引用的项目中,将调用I
ICompositionRootComposer
实例来注册服务、类型等
public interface ICompositionRootComposer
{
void Compose(ICompositionConfigurator configurator);
}
在构建层次结构中直接引用的项目中,将调用ICompositionRootComposer
的实现,并在基础IoC容器中正确注册服务
当我试图在项目中注册服务时会出现问题,我在项目中设置了一个生成后任务,将生成的dll复制到web项目的调试文件夹:
cp -R $(TargetDir)"assembly and symbol name"* $(SolutionDir)src/"webproject path"/bin/Debug/netcoreapp1.1
我正在加载程序集:(灵感:)
有了它,我可以加载程序集并调用项目ICompositionRootComposer
实现
但问题是它似乎无法识别我的任何类型
使用调用我的配置程序时
configurator.RegisterTransiantService<IFoo, Foo>();
configurator.RegisterTransiantService();
它应该在国际奥委会注册IFoo和Foo。但是在调试时,我无法获得类型的信息,即通过Visual Studio代码中调试控制台中的typeof(Foo)获取信息。您知道ASP.NET Core有自己的内置机制吗?它可以根据您的需要轻松地切换到其他IoC容器,我认为您不需要重新设计它 这里需要做的是使用反射生成一个泛型方法,然后调用,如下所示:
public void ConfigureServices(IServiceCollection services)
{
var myAssembly = LoadAssembly();
// find first interface
var firstInterfaceType = myAssembly.DefinedTypes.FirstOrDefault(t => t.IsInterface).GetType();
// find it's implementation
var firstInterfaceImplementationType = myAssembly.DefinedTypes.Where(t => t.ImplementedInterfaces.Contains(firstInterfaceType)).GetType();
// get general method info
MethodInfo method = typeof(IServiceCollection).GetMethod("AddTransient");
// provide types to generic method
MethodInfo generic = method.MakeGenericMethod(firstInterfaceType, firstInterfaceImplementationType);
// register your types
generic.Invoke(services, null);
}
我找到了解决问题的办法 事实证明,我将属性
preserveComilationContext
设置为true,这就是调试器不注册手动复制的程序集的原因。
当我从web项目csproj文件中删除该属性时,一切正常。亡灵巫术
您可以为旧的Assembly.LoadFile创建一个包装器类来完成此操作这还有一个额外的好处,即通过在旧代码库中应用搜索和替换更改,您可以保持与dotnet none core的向后兼容
您需要通过nuget添加
System.Runtime.Loader
namespace System.Reflection
{
public class Assembly2
{
public static System.Reflection.Assembly LoadFile(string path)
{
System.Reflection.Assembly ass = null;
#if NET_CORE
// Requires nuget - System.Runtime.Loader
ass = System.Runtime.Loader.AssemblyLoadContext.Default
.LoadFromAssemblyPath(path);
#else
ass = System.Reflection. Assembly.LoadFile(path);
#endif
// System.Type myType = ass.GetType("Custom.Thing.SampleClass");
// object myInstance = Activator.CreateInstance(myType);
return ass;
}
}
}
我很高兴获得.net核心DI机制的奖励,但我希望保留项目中实现的注册,代码放在项目中的位置。您的方法似乎保持了与web项目外部项目的硬耦合。
ConfigureService
是ASP.NET中依赖项注入的合成根。您可以在自己实现的roots中使用相同的方法,但我仍然不确信——不管怎样,我认为我们已经偏离了主题。我问为什么我复制的项目中的类型无法加载,即使我可以在同一项目中调试我的编写器。正如我所说,您可以在自己的代码中使用相同的方法。你试过了吗?我实际上连接到了AssemblyLoadContext.Resolving
事件,以帮助加载上下文加载它自己无法加载的程序集。
namespace System.Reflection
{
public class Assembly2
{
public static System.Reflection.Assembly LoadFile(string path)
{
System.Reflection.Assembly ass = null;
#if NET_CORE
// Requires nuget - System.Runtime.Loader
ass = System.Runtime.Loader.AssemblyLoadContext.Default
.LoadFromAssemblyPath(path);
#else
ass = System.Reflection. Assembly.LoadFile(path);
#endif
// System.Type myType = ass.GetType("Custom.Thing.SampleClass");
// object myInstance = Activator.CreateInstance(myType);
return ass;
}
}
}