我使用Ninject但这适用于任何IoC。 我有一个运行后台线程的单例,该线程运行整个程序的生命周期。每5分钟后台线程启动一些工作人员。这些工人使用autofac进行注射
Func<IEnumerable<IWorker>>
但这只涉及一些问题,让我解释一下,我的一些工作者依赖于存储库,每个存储库都依赖于具有线程范围的Entity框架上下文(它将在线程结束时处理)。这意味着当执行autofac并获得一个工作列表时,它们的范围将位于与程序具有相同生命周期的后台线程上,不适合拥有适用于整个应用程序的EF上下文。每个worker Execute方法都是在一个单独的线程中执行的,但是这样做就没有关系,因为Ninject仍然只会监听永远不会结束的主后台线程。
如果你问我,我现在以一种非常丑陋的方式解决了这个问题,我注入了一个非通用的工厂
Func<Type, object>
然后我要求程序集返回IWorker接口的所有具体类型,然后我使用工厂方法在每个工作线程中调用它们(这意味着范围将仅用于工作线程而不是背景thead),这是有效的,但它很难看,我不能把IWorkers存在,这意味着我不能再运行我的单元测试了。
你们有一个很好的解决方案吗? :D谢谢
编辑:感谢Remo的帮助,命名范围部分现在可以正常工作,但原始问题仍然存在..这是我的测试代码
WorkManager
internal class WorkflowManager : IWorkflowManager
{
private readonly Func<IWorker> testWorker;
private BackgroundWorker backgroundWorker;
public WorkflowManager(Func<IWorker> testWorker)
{
this.testWorker = testWorker;
}
public void Start()
{
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += DoBackgroundWork;
backgroundWorker.RunWorkerAsync();
}
public void Stop()
{
}
private void DoBackgroundWork(object sender, DoWorkEventArgs e)
{
var test = testWorker();
}
}
其绑定
kernel.Bind<IWorkflowManager>().To<WorkflowManager>().InSingletonScope();
工人
internal class TestWorker : IWorker, IDisposable
{
public TestWorker()
{
System.Diagnostics.Debug.WriteLine("Contructed!");
}
~TestWorker()
{
System.Diagnostics.Debug.WriteLine("Deconstructed!");
}
public void Dispose()
{
System.Diagnostics.Debug.WriteLine("Disposed!");
}
}
结合
kernel.Bind<IWorker>().To<TestWorker>().InCallScope();
只有构造函数被调用...:/
答案 0 :(得分:3)
使用https://github.com/ninject/ninject.extensions.namedscope/wiki/InCallScope。使用此作用域将在工作程序从缓存中收集或释放垃圾时处置依赖项。
像这样设置应用程序。下一个版本不再需要此解决方法。
public static class NinjectMVC3
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestModule));
DynamicModuleUtility.RegisterModule(typeof(HttpApplicationInitializationModule));
bootstrapper.Initialize(CreateKernel);
bootstrapper.Kernel.Rebind<IResolutionRoot>().To<ContextPreservingResolutionRoot>();
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Unbind<IResolutionRoot>();
}
}