创建实例并解析依赖
Create instance and resolve dependencies
我有在主项目中引用的 c# 库。图书馆
- 获取主项目程序集;
- 使用
System.Reflection
; 检索所有类型
- 应该使用
Activator.CreateInstance
创建类型(我不确定这是最好的方法)。
库对主项目一无所知,只有一个可以通过反射获取的元数据。 如何解决依赖关系?
private readonly Assembly _assembly;
public Injector()
{
_assembly = Assembly.GetEntryAssembly();
}
public List<string> GetTypes()
{
return _assembly
.GetTypes()
.Select(x => x.FullName)
.ToList();
}
public object GetType(string typeName)
{
Type type = _assembly
.GetTypes()
.First(x => x.FullName == typeName);
object instance = Activator.CreateInstance(type);
return instance;
}
可能的问题:不同的IoC容器(第三方库,自己写的)。
在不强迫用户提供大量设置的情况下,处理此问题并使库更加自动化的最佳方法是什么?如果不可能,您能否提供任何其他解决方案?谢谢。
编辑: 如何为 Activator.CreateInstance
中的实例提供依赖项或直接从主(源)项目创建实例?应该允许创建包含在主项目中的任何实例。是的,主项目也对库一无所知。因此,最好在主项目中进行最少的代码更改。
编辑 2: 该库不会在源项目中使用,它将有自己的 UI 接口。例如,Swagger API
只要解析的库在同一文件夹下(或在 GAC 中),依赖关系就会自动解析
如果库在特定文件夹下,自动解析可能会失败,但您可以通过 AppDomain.AssemblyResolve 事件处理。
此外,您似乎正在尝试实现一种 plugin/addon 主机,也许您可以尝试使用 Managed Extensibility Framework 而不是通过反射手动实现解决方案。
编辑: 以下是事件使用的代码片段,但需要根据您的环境进行调整
static Injector()
{
// Usage of static constructor because we need a unique static handler
// But feel free to move this part to a more global location
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string foundAssemblyPath = string.Empty;
// args.Name contains name of the missing assembly
// some project-specific and environment-specific code should be added here to manually resolve the dependant library
// In this example I will consider that the libraries are located under /plugins folder
foundAssemblyPath = $@"{Path.GetDirectoryName(Application.StartupPath)}\plugins\{args.Name}.dll";
return Assembly.LoadFile(foundAssemblyPath);
}
我找到了处理这个问题的方法。
.NET Standard 具有一个新接口 IServiceProvider
,必须由 Startup.ConfigureServices()
中的任何 IoC 容器实现。我们可以将此 IServiceProvider
传递给库构造函数并使用方法 GetService(Type type)
来创建具有所有解析的依赖项注入的服务。
源项目(例如 Startup.cs 中的 Autofac 容器):
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var builder = new ContainerBuilder();
builder.RegisterType<CalculationService>().As<ICalculationService>();
builder.RegisterType<Logger>().As<ILogger>();
builder.Populate(services);
var container = builder.Build();
return new AutofacServiceProvider(container);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider diService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
var injection = new Injector(diService);
var result = injection.RunMethod(typeof(ICalculationService).FullName, "Sum", new int[] { 1, 2, 3 });
}
图书馆项目:
public class Injector
{
private readonly Assembly _assembly;
private readonly IServiceProvider _serviceProvider;
public Injector(IServiceProvider serviceProvider)
{
_assembly = Assembly.GetEntryAssembly();
_serviceProvider = serviceProvider;
}
public object RunMethod(string className, string methodName, params object[] parameters)
{
var classType = _assembly
.GetType(className);
object instance = _serviceProvider.GetService(classType);
var method = classType.GetMethod(methodName);
var result = method.Invoke(instance, parameters);
return result;
}
}
我有在主项目中引用的 c# 库。图书馆
- 获取主项目程序集;
- 使用
System.Reflection
; 检索所有类型
- 应该使用
Activator.CreateInstance
创建类型(我不确定这是最好的方法)。
库对主项目一无所知,只有一个可以通过反射获取的元数据。 如何解决依赖关系?
private readonly Assembly _assembly;
public Injector()
{
_assembly = Assembly.GetEntryAssembly();
}
public List<string> GetTypes()
{
return _assembly
.GetTypes()
.Select(x => x.FullName)
.ToList();
}
public object GetType(string typeName)
{
Type type = _assembly
.GetTypes()
.First(x => x.FullName == typeName);
object instance = Activator.CreateInstance(type);
return instance;
}
可能的问题:不同的IoC容器(第三方库,自己写的)。
在不强迫用户提供大量设置的情况下,处理此问题并使库更加自动化的最佳方法是什么?如果不可能,您能否提供任何其他解决方案?谢谢。
编辑: 如何为 Activator.CreateInstance
中的实例提供依赖项或直接从主(源)项目创建实例?应该允许创建包含在主项目中的任何实例。是的,主项目也对库一无所知。因此,最好在主项目中进行最少的代码更改。
编辑 2: 该库不会在源项目中使用,它将有自己的 UI 接口。例如,Swagger API
只要解析的库在同一文件夹下(或在 GAC 中),依赖关系就会自动解析 如果库在特定文件夹下,自动解析可能会失败,但您可以通过 AppDomain.AssemblyResolve 事件处理。
此外,您似乎正在尝试实现一种 plugin/addon 主机,也许您可以尝试使用 Managed Extensibility Framework 而不是通过反射手动实现解决方案。
编辑: 以下是事件使用的代码片段,但需要根据您的环境进行调整
static Injector()
{
// Usage of static constructor because we need a unique static handler
// But feel free to move this part to a more global location
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string foundAssemblyPath = string.Empty;
// args.Name contains name of the missing assembly
// some project-specific and environment-specific code should be added here to manually resolve the dependant library
// In this example I will consider that the libraries are located under /plugins folder
foundAssemblyPath = $@"{Path.GetDirectoryName(Application.StartupPath)}\plugins\{args.Name}.dll";
return Assembly.LoadFile(foundAssemblyPath);
}
我找到了处理这个问题的方法。
.NET Standard 具有一个新接口 IServiceProvider
,必须由 Startup.ConfigureServices()
中的任何 IoC 容器实现。我们可以将此 IServiceProvider
传递给库构造函数并使用方法 GetService(Type type)
来创建具有所有解析的依赖项注入的服务。
源项目(例如 Startup.cs 中的 Autofac 容器):
// This method gets called by the runtime. Use this method to add services to the container.
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var builder = new ContainerBuilder();
builder.RegisterType<CalculationService>().As<ICalculationService>();
builder.RegisterType<Logger>().As<ILogger>();
builder.Populate(services);
var container = builder.Build();
return new AutofacServiceProvider(container);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider diService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMvc();
var injection = new Injector(diService);
var result = injection.RunMethod(typeof(ICalculationService).FullName, "Sum", new int[] { 1, 2, 3 });
}
图书馆项目:
public class Injector
{
private readonly Assembly _assembly;
private readonly IServiceProvider _serviceProvider;
public Injector(IServiceProvider serviceProvider)
{
_assembly = Assembly.GetEntryAssembly();
_serviceProvider = serviceProvider;
}
public object RunMethod(string className, string methodName, params object[] parameters)
{
var classType = _assembly
.GetType(className);
object instance = _serviceProvider.GetService(classType);
var method = classType.GetMethod(methodName);
var result = method.Invoke(instance, parameters);
return result;
}
}