我试图使用自定义属性来定义我希望我的框架容器加载的外部库中的模块。我能够扫描程序集,查找并验证我的类型,并返回实例化的IModules列表。然而,当我试图解析在外部模块中注册的类型时,类型无法解析。
针对。net标准2.0的主库
public static List<IModule> DiscoverContainerModules()
{
var modules = new List<IModule>();
var assemblies = DiscoverAssemblies();
foreach (var assembly in assemblies)
{
modules.AddRange(from type in assembly.GetTypes()
where type.GetCustomAttribute<AppkitModuleAttribute>() != null
where type.IsAssignableTo<IModule>()
select Activator.CreateInstance(type) into module
select module as IModule);
}
return modules;
}
注册模块的扩展方法
public static void UseAppkitModules(this ContainerBuilder builder)
{
var modules = AppkitPluginDiscovery.DiscoverContainerModules();
foreach (var module in modules)
{
builder.RegisterModule(module);
}
}
基于。net Core 6.0的托管应用程序
builder.UseAppkitModules();
最后是另一个。net标准2.0库中的模块示例
[AppkitModule(nameof(DisplayModule))]
public class DisplayModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c =>
{
var conductor = c.Resolve<IConductor>();
var logger = c.Resolve<ILogger>();
return new DisplaySubsystem(
conductor: conductor,
logger: logger);
});
}
}
该模块工作良好,如果我只是新建它的建设者。RegisterModule(新DisplayModule ());我已经确认Load方法是用反射方法调用的。为什么用Activator创建模块实例的行为不同?我还确认程序集已加载。
我已经将模块移动到父库中,它也失败了。我把所有的扩展方法分解成一个大的代码块,得到了相同的结果。我甚至用Activator创建了实例,得到了相同的结果。
已解决:
问题的根源是我加载和扫描应用了自定义属性的程序集的方法。我用的是Assembly.LoadFile(path)
。它似乎没有提供加载我的模块所需的依赖关系。我更新了使用Assembly.LoadFrom(path)
的方法,所有模块和类型都可以完美地解决。
完整解决方案-负载组件
private static List<Assembly> LoadReferencedAssemblies()
{
var assemblies = new List<Assembly>();
var path = AppContext.BaseDirectory;
var directory = new DirectoryInfo(path);
if (!directory.Exists) return assemblies;
var libraries = directory.GetFiles("*.dll");
assemblies.AddRange(libraries.Select(fileInfo => Assembly.LoadFrom(fileInfo.FullName)));
return assemblies;
}
获取具有自定义属性的程序集
private static List<Assembly> DiscoverAssemblies()
{
var assemblies = new List<Assembly>();
var attributes = DiscoverAttributes();
var domain = LoadReferencedAssemblies();
foreach (var assembly in domain)
{
assemblies.AddRange(
from type in assembly.GetTypes()
where attributes.Any(attribute => type.GetCustomAttribute(attribute) != null)
where !assemblies.Contains(assembly)
select assembly);
}
return assemblies;
}
获取具有模块属性的所有类型
public static List<AppkitAssemblyType> DiscoverModules()
{
var modules = new List<AppkitAssemblyType>();
modules.AddRange(
from assembly in AppkitAssemblies
from type in assembly.GetTypes()
where type.GetCustomAttribute<AppkitModuleAttribute>() != null
select new AppkitAssemblyType(type));
return modules;
}
<<p>Builder扩展/strong>
public static ContainerBuilder RegisterAppkitModules(this ContainerBuilder builder)
{
var modules = AppkitPluginDiscovery.DiscoverModules();
foreach (var module in modules)
{
builder.RegisterAssemblyModules(module.Type, module.Assembly);
}
return builder;
}
引用程序集中的示例模块
[AppkitModule(nameof(DisplayModule))]
public class DisplayModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DisplaySubsystem>().AsSelf().SingleInstance();
}
}
Finally Container Configuration
builder.RegisterAppkitModules()