将温莎城堡注入的依赖项传递给并行线程 - Dispose() 问题

发布于 2024-10-24 11:26:10 字数 2109 浏览 2 评论 0原文

我使用 ASP.NET MVC 和 Castle Windsor 作为我的 IoC 容器,并将组件生活方式设置为 PerWebRequest。我的存储库(即注入的依赖项)在构造函数中创建实体框架的 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();
    }
}

为了确保没有内存泄漏并且调用我的存储库的 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");
    }
}

其他人如何解决这个问题?如何将依赖项传递给并行线程?

提前致谢。

I'm using ASP.NET MVC with Castle Windsor as my IoC container with the component lifestyle set to PerWebRequest. My repository (which is the dependency that's injected) creates an instance of Entity Framework's ObjectContext in the constructor and I store that in a private instance variable. My repository implements IDisposable and inside my Dispose method, I dispose the ObjectContext. I think all of this is pretty standard and here's a simplified illustration:

Repository:

 public class Repository : IRepository {

    private MyContext _dc; // MyContext inherits from ObjectContext

    public Repository() {
        _dc = new MyContext();
    }

    public void Dispose() {;
        _dc.Dispose();
    }
}

To ensure that there's no memory leak and that my Repository's Dispose() is called, I override DefaultControllerFactory's ReleaseController method to release Windsor's container:

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);
        }
    }

I think all of this is pretty standard. However, I'd like to spin off a parallel thread, and inside that parallel thread utilize the IRepository dependency. My problem is that my repository will have already been disposed by the time I use it:

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");
    }
}

How do other people solve this problem? How do you pass your dependencies to a parallel thread?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

陌生 2024-10-31 11:26:10

创建一个新的存储库实例。 ObjectContext 的构建成本低廉。

或者,您可以将处理存储库的责任附加到长时间运行的线程。我搞乱了它,我认为对代码的这些更改将解决您的问题:

在您的 WindsorControllerFactory 中

    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);
    }

、在 HomeController 中

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;
}

Create a new Repository instance. ObjectContexts are inexpensive to construct.

OR, you could attach the responsibility of disposing the Repository to the long running thread. I messed around with it, I think these alterations to your code will solve your problem:

In your WindsorControllerFactory

    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);
    }

In HomeController

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");
    }
}

And the new base controller

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文