Ninject ActivationBlock 作为工作单元

发布于 2024-12-23 06:37:46 字数 1849 浏览 1 评论 0原文

我有一个带有 MVVM 的 WPF 应用程序。假设从 ViewModel 向下的对象组合如下所示:

MainViewModel
    OrderManager
        OrderRepository
            EFContext
        AnotherRepository
            EFContext
    UserManager
        UserRepository
            EFContext

我最初的方法是使用 EFContext 上的 .InCallScope() 和其他所有内容使用 .InTransientScope() 将依赖项(从 ViewModelLocator)注入到我的视图模型中。这导致能够跨多个业务层对象(管理器)执行“业务事务”,这些对象最终在下面共享相同的实体框架上下文。我会简单地 Commit() 在工作单元类型场景的末尾表示上下文。

这按预期工作,直到我意识到我不希望在视图模型级别长期存在实体框架上下文,跨多个操作描述的数据完整性问题 此处。我想做一些类似于我的 Web 项目的事情,我在实体框架上下文中使用 .InRequestScope() 。在我的桌面应用程序中,我将定义一个工作单元,如果您愿意的话,它将充当业务事务,通常它将把所有内容包装在按钮单击或类似事件/命令中。看来使用 Ninject 的 ActivationBlock 可以为我做到这一点。

internal static class Global
{
    public static ActivationBlock GetNinjectUoW()
    {            
        //assume that NinjectSingleton is a static reference to the kernel configured with the necessary modules/bindings
        return new ActivationBlock(NinjectSingleton.Instance.Kernel);
    }   
}

在我的代码中,我打算这样使用它:

//Inside a method that is raised by a WPF Button Command ...
using (ActivationBlock uow = Global.GetNinjectUoW())
{
    OrderManager orderManager = uow.Get<OrderManager>();
    UserManager userManager = uow.Get<UserManager>();

    Order order = orderManager.GetById(1);
    UserManager.AddOrder(order);
    ....
    UserManager.SaveChanges();
}

问题:

  1. 对我来说,这似乎复制了我在网络上开展业务的方式,这种方法是否有我错过的本质上的错误?
  2. 我是否正确理解所有 .Get<>使用激活块的调用会产生该块本地的“单例”吗?我的意思是,无论我请求 OrderManager 多少次,它总是会在块内给我相同的一个。如果 OrderManager 和 UserManager 在下面组成相同的存储库(例如 SpecialRepository),则两者都将指向存储库的同一实例,并且显然下面的所有存储库共享实体框架上下文的相同实例。

I have a WPF application with MVVM. Assuming object composition from the ViewModel down looks as follows:

MainViewModel
    OrderManager
        OrderRepository
            EFContext
        AnotherRepository
            EFContext
    UserManager
        UserRepository
            EFContext

My original approach was to inject dependencies (from the ViewModelLocator) into my View Model using .InCallScope() on the EFContext and .InTransientScope() for everything else. This results in being able to perform a "business transaction" across multiple business layer objects (Managers) that eventually underneath shared the same Entity Framework Context. I would simply Commit() said context at the end for a Unit of Work type scenario.

This worked as intended until I realized that I don't want long living Entity Framework contexts at the View Model level, data integrity issues across multiple operations described HERE. I want to do something similar to my web projects where I use .InRequestScope() for my Entity Framework context. In my desktop application I will define a unit of work which will serve as a business transaction if you will, typically it will wrap everything within a button click or similar event/command. It seems that using Ninject's ActivationBlock can do this for me.

internal static class Global
{
    public static ActivationBlock GetNinjectUoW()
    {            
        //assume that NinjectSingleton is a static reference to the kernel configured with the necessary modules/bindings
        return new ActivationBlock(NinjectSingleton.Instance.Kernel);
    }   
}

In my code I intend to use it as such:

//Inside a method that is raised by a WPF Button Command ...
using (ActivationBlock uow = Global.GetNinjectUoW())
{
    OrderManager orderManager = uow.Get<OrderManager>();
    UserManager userManager = uow.Get<UserManager>();

    Order order = orderManager.GetById(1);
    UserManager.AddOrder(order);
    ....
    UserManager.SaveChanges();
}

Questions:

  1. To me this seems to replicate the way I do business on the web, is there anything inherently wrong with this approach that I've missed?
  2. Am I understanding correctly that all .Get<> calls using the activation block will produce "singletons" local to that block? What I mean is no matter how many times I ask for an OrderManager, it'll always give me the same one within the block. If OrderManager and UserManager compose the same repository underneath (say SpecialRepository), both will point to the same instance of the repository, and obviously all repositories underneath share the same instance of the Entity Framework context.

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

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

发布评论

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

评论(2

清风无影 2024-12-30 06:37:46

这两个问题都可以回答“是”:

  1. 是 - 这是您不应该做的服务地点 是的
  2. ,您理解正确

Both questions can be answered with yes:

  1. Yes - this is service location which you shouldn't do
  2. Yes you understand it correctly
蝶…霜飞 2024-12-30 06:37:46

适当的工作单元范围,在 Ninject.Extensions.UnitOfWork 中实现,解决了这个问题。

设置:

_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();

使用:

using(UnitOfWorkScope.Create()){
    // resolves, async/await, manual TPL ops, etc    
}

A proper unit-of-work scope, implemented in Ninject.Extensions.UnitOfWork, solves this problem.

Setup:

_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();

Usage:

using(UnitOfWorkScope.Create()){
    // resolves, async/await, manual TPL ops, etc    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文