gpt4 book ai didi

c# - ninject 将 iunitofwork 注入(inject)存储库范围的属性

转载 作者:太空宇宙 更新时间:2023-11-03 15:49:06 25 4
gpt4 key购买 nike

让我从我当前的设置开始,然后解释我想要实现的目标。我们正在使用 NHibernate 并尝试使用 Ninject 实现 IRepository/IUnitOfWork 模式。理想情况下,无论是 ASP.Net、WCF 还是其他任何应用程序,它都应该适用于使用该代码的任何应用程序。

工作单元

public interface IUnitOfWork
{
object Add(object obj);//all other supported CRUD operations we want to expose
void Commit();
void Rollback();
}

工作单元

public class UnitOfWork : IUnitOfWork
{
private readonly ISessionFactory _sessionFactory;
private readonly ISession _session;
private readonly ITransaction _transaction;

public UnitOfWork(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
_session = _sessionFactory.OpenSession();
_transaction = _session.BeginTransaction();
}

public object Add(object obj)
{
return _session.Save(obj);
}

public void Commit()
{
if(!_transaction.IsActive)
{throw new Exception("some error");}
_transaction.Commit();
}

public void Rollback()
{
if (!_transaction.IsActive)
{
throw new Exception("some other error");
}
_transaction.Rollback();
}
}

IRepository

public interface IRepository<TEntity, TId> where TEntity : class
{
TId Add(TEntity item);//add other missing CRUD operations
}

通用存储库

public class GenericRepository<TEntity, TId> : IRepository<TEntity, TId>
where TEntity : class
{
public TId Add(TEntity item)
{
throw new NotImplementedException();
}
}

我正在使用 Ninject 作为我的 IOC 容器。目标是在创建 UnitOfWork 的生命周期中重用相同的 IUnitOfWork。无论调用应用程序是什么,我都希望实现的生命周期能够正常工作,否则我会像大多数在线建议一样使用 InRequestScope。我能够做这样的事情:

//constructor
public MyService(IUnitOfWork uow, IRepository<User, int> userRepo, IRepository<Cat, int> catRepo)
{
_uow = uow; _userRepo = userRepo; _catRepo = catRepo;
}

//method in same class
public void DoSomeWork()
{
_userRepo.Add(someUser);
_catRepo.Add(someCat);
_uow.Commit();

//rollback on error
}

我的绑定(bind)设置如下:

Bind<IUnitOfWork>.To<UnitOfWork>().InCallScope();
Bind(typeof(IRepository<,>)).To(typeof(GenericRepository<,>));

这个绑定(bind)配置实际上适用于上面的 MyService,它将在构造函数中创建一次 UnitOfWork 并且它也会对 IRepo impls 使用相同的 UnitOfWork,无论向下多少层他们实际上可能是。

但我希望能够将 IUnitOfWork 完全隐藏在应用程序之外。我宁愿提供一些可以放置在方法之上的 TransactionAttribute,它将在入口时创建 IUnitOfWork,并且相同的实例将被注入(inject)到 TransactionAttribute 范围内的所有 future 对 IUnitOfWork 的请求。它会相应地负责提交和回滚。所以之前的代码会变成这样:

//constructor
public MyService(IRepository<User, int> userRepo, IRepository<Cat, int> catRepo)
{
_uow = uow; _userRepo = userRepo; _catRepo = catRepo;
}

//method in same class
[Transaction]
public void DoSomeWork()
{
_userRepo.Add(someUser);
_catRepo.Add(someCat);
}

是否有任何类型的绑定(bind)设置可以让我用这样的 [Transaction] 标记一个方法?我愿意对 IUnitOfWork 和 IRepository 的东西进行一些小的重组,服务层代码只是废代码,所以我可以在那里非常灵活。

最佳答案

首先,注入(inject)不适用于

[Transaction]
public void DoSomeWork()
{
_userRepo.Add(someUser);
_catRepo.Add(someCat);
}

毕竟容器不知道你要调用什么样的方法,什么时候调用。

更进一步,因为您希望它与 WebApps、WCF、.. 一起工作,也许是一些 quartz 作业或其他:您必须决定是否要绑定(bind) IUnitOfWork 的生命周期>/Repository/NHibernate Session 到使用它的对象的生命周期(如 MyService),或者如果您希望服务生命周期更长(例如单例)并为方法调用创建一个新的 NHibernate Session:

[Transaction]
public void DoSomeWork()
{
_userRepo.Add(someUser);
_catRepo.Add(someCat);
}

这实际上可以通过 AOP 实现, 要么使用 FodyPostSharp .或者,您也可以考虑使用装饰器模式来实现这一点(例如参见 here )。但是,如果我没记错的话,ninject 目前缺少一些支持 easz 装饰器处理的细节。

作为 [Transaction] 属性的替代方案,您可以从显式控制一切开始:

public interface IUnitOfWork
{
IUnitOfWorkSession Begin(); // starts a session and transaction
}

public interface IUnitOfWorkSession : IDisposable
{
void Commit();
void Dispose(); // performs rollback in case no commit was performed
}

由于您将需要访问其他对象中的 nhibernate Session,例如 _userRepo_catRepo 您还需要一种方法来访问Session 独立于容器,因为它与实例化对象的方式/时间无关。当然,您可以像这样传递它:

public void DoSomeWork()
{
using(IUnitOfWorkSession session = _unitOfWork.Begin())
{
_userRepo.Add(session, someUser);
_catRepo.Add(session, someCat);
session.Commit();
}
}

但这并不是很酷。因此,您需要使用类似 ThreadLocal 的东西(如果您使用的是 async/await,这可能会有问题)或 SynchronizationContext 本地存储。

现在,如果您已经做到了这一点,您可以考虑进行 AOP。AOP 将有两个处理两件事:

  • 获得对 IUnitOfWork 的访问权。
    • 可以通过编织它作为额外的 ctor 参数来完成
    • 或者它可以检查是否已经有一个,如果有,它可以使用这个,如果没有,它可以抛出或编织参数......
  • 使用与上面相同的代码包装装饰方法:
public void DoSomeWork()
{
using(IUnitOfWorkSession session = _unitOfWork.Begin()) // weave this
{
_userRepo.Add(session, someUser);
_catRepo.Add(session, someCat);
session.Commit(); // weave this
}
}

关于c# - ninject 将 iunitofwork 注入(inject)存储库范围的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26665351/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com