我正在使用带有Castle Windsor的ASP.NET MVC作为我的IoC容器,其组件生活方式设置为PerWebRequest。我的存储库(它是注入的依赖项)在构造函数中创建了Entity Framework的ObjectContext实例,并将其存储在私有实例变量中。我的存储库实现了IDisposable,在我的Dispose方法中,我处理了ObjectContext。我认为所有这些都是非常标准的,这是一个简化的例子:
存储库:
public class Repository : IRepository {
private MyContext _dc; // MyContext inherits from ObjectContext
public Repository() {
_dc = new MyContext();
}
public void Dispose() {;
_dc.Dispose();
}
}
为了确保没有内存泄漏并且我的Repository的Dispose()被调用,我覆盖DefaultControllerFactory的ReleaseController方法来释放Windsor的容器:
public class WindsorControllerFactory : DefaultControllerFactory {
IWindsorContainer _container;
public WindsorControllerFactory(IWindsorContainer container) {
_container = container;
// Do stuff to register all controller types
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
// Do stuff to resolve dependency
}
public override void ReleaseController(IController controller) {
// by releasing the container, Windsor will call my Dispose() method on my repository
_container.Release(controller);
base.ReleaseController(controller);
}
}
我认为所有这些都非常标准。但是,我想脱离并行线程,并在该并行线程内部利用IRepository依赖。我的问题是我的存储库在我使用它时已经被处理掉了:
public class HomeController : Controller {
IRepository _repository;
public HomeController(IRepository repository) {
_repository = repository;
}
public ActionResult Index() {
var c = _repository.GetCompany(34);
new Task(() => {
System.Threading.Thread.Sleep(2000); // simulate long running task
// will throw an error because my repository (and therefore, ObjectContext) will have been disposed.
var c2 = _repository.GetCompany(35);
}).Start();
return Content(c.Name, "text/plain");
}
}
其他人如何解决这个问题?如何将依赖项传递给并行线程?
提前致谢。
答案 0 :(得分:4)
创建一个新的Repository实例。 ObjectContexts的构造成本低廉。
或者,您可以将处理存储库的责任附加到长时间运行的线程。我搞砸了它,我认为这些代码的改动将解决你的问题:
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
IController controller;
// Do stuff to resolve dependency
if(controller is LongTaskController)
{
((LongTaskController) controller).CompleteLongTask += (sender, args) => _container.Release(controller);
}
}
public override void ReleaseController(IController controller)
{
// by releasing the container, Windsor will call my Dispose() method on my repository
if(!(controller is LongTaskController && ((LongTaskController)controller).HasLongTask)
{
_container.Release(controller);
}
base.ReleaseController(controller);
}
public class HomeController : LongTaskController
{
private readonly IRepository _repository;
public HomeController(IRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var c = _repository.GetCompany(34);
DoLongTask(() =>
{
Thread.Sleep(200);
var c2 = _repository.GetCompany(35);
});
return Content(c.Name, "text/plain");
}
}
public abstract class LongTaskController: Controller,IHasLongTask
{
private bool _hasLongTask;
public bool HasLongTask { get { return _hasLongTask; } }
public event EventHandler CompleteLongTask;
void IHasLongTask.DoLongTask(Action action) { DoLongTask(action); }
protected void DoLongTask(Action action)
{
_hasLongTask = true;
if (CompleteLongTask == null)
{
throw new NullReferenceException("Controller.CompleteLongTask cannot be null when Controller does a long running task.");
action += () => CompleteLongTask(this, EventArgs.Empty);
}
new Task(action).Start();
}
}
public interface IHasLongTask
{
bool HasLongTask { get; }
void DoLongTask(Action action);
event EventHandler CompleteLongTask;
}