加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net – 如何使用依赖注入将工作单元容器传递到存储库的构造

发布时间:2020-12-16 09:33:23 所属栏目:asp.Net 来源:网络整理
导读:我正在尝试研究如何在ASP.NET Web应用程序中完成我的Repository模式的实现. 目前,我有一个每个域类的存储库接口,用于定义例如加载和保存该类的实例. 每个存储库接口都由一个执行NHibernate工作的类实现. Castle Windsor根据web.config将类的DI排序到界面中.
我正在尝试研究如何在ASP.NET Web应用程序中完成我的Repository模式的实现.

目前,我有一个每个域类的存储库接口,用于定义例如加载和保存该类的实例.

每个存储库接口都由一个执行NHibernate工作的类实现. Castle Windsor根据web.config将类的DI排序到界面中.下面提供了一个实现类的示例:

public class StoredWillRepository : IStoredWillRepository
  {
    public StoredWill Load(int id)
    {
      StoredWill storedWill;
      using (ISession session = NHibernateSessionFactory.OpenSession())
      {
        storedWill = session.Load<StoredWill>(id);
        NHibernateUtil.Initialize(storedWill);
      }
      return storedWill;
    }

    public void Save(StoredWill storedWill)
    {
      using (ISession session = NHibernateSessionFactory.OpenSession())
      {
        using (ITransaction transaction = session.BeginTransaction())
        {
          session.SaveOrUpdate(storedWill);
          transaction.Commit();
        }
      }
    }
  }

正如前一个线程所指出的,存储库类需要接受一个工作单元容器(即ISession),而不是在每个方法中实例化它.

我预计工作单元容器将在需要时由每个aspx页面创建(例如,在属性中).

然后,当Windsor为我创建时,如何指定将此工作单元容器实例传递到StoredWillRepository的构造函数中?

或者这种模式完全错了?

再次感谢您的建议.

大卫

解决方法

我有一个基于NHibernate构建的持久性框架,用于一些Web应用程序.它隐藏了IRepository和IRepository< T>之后的NH实现.接口,具有Unity提供的具体实例(因此我理论上可以相当容易地将NHibernate替换为实体框架).

由于Unity没有(或者至少我使用的版本没有)支持传递除了依赖注入本身之外的构造函数参数,因此无法传入现存的NH ISession;但我确实希望UOW中的所有对象共享同一个ISession.

我通过拥有一个控制存储库类来解决这个问题,该类在每个线程的基础上管理对ISession的访问:

public static ISession Session
    {
        get
        {
            lock (_lockObject)
            {
                // if a cached session exists,we'll use it
                if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
                {
                    return (ISession)PersistenceFrameworkContext.Current.Items[NHibernateRepository.SESSION_KEY];
                }
                else
                {
                    // must create a new session - note we're not caching the new session here... that's the job of
                    // BeginUnitOfWork().
                    return _factory.OpenSession(new NHibernateInterceptor());
                }
            }
        }
    }

在此示例中,PersistenceFrameworkContext.Current.Items访问IList< object>如果不在Web上下文中,则存储在ThreadStatic中;如果在Web上下文中,则存储在HttpContext.Current.Items中(以避免线程池问题).对属性的第一次调用从存储的工厂实例中实例化ISession,后续调用只是从存储中检索它.锁定会略微降低速度,但不会像锁定appdomain范围的静态ISession实例那样多.

然后我有BeginUnitOfWork和EndUnitOfWork方法来处理UOW – 我特别禁止嵌套的UOW,因为坦率地说它们很难管理.

public void BeginUnitOfWork()
    {
        lock (_lockObject)
        {
            if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
                EndUnitOfWork();

            ISession session = Session;
            PersistenceFrameworkContext.Current.Items.Add(SESSION_KEY,session);
        }
    }

    public void EndUnitOfWork()
    {
        lock (_lockObject)
        {
            if (PersistenceFrameworkContext.Current.Items.ContainsKey(SESSION_KEY))
            {
                ISession session = (ISession)PersistenceFrameworkContext.Current.Items[SESSION_KEY];
                PersistenceFrameworkContext.Current.Items.Remove(SESSION_KEY);
                session.Flush();
                session.Dispose();
            }
        }
    }

最后,一对方法提供对特定于域类型的存储库的访问:

public IRepository<T> For<T>()
        where T : PersistentObject<T>
    {
        return Container.Resolve<IRepository<T>>();
    }

    public TRepository For<T,TRepository>()
        where T : PersistentObject<T>
        where TRepository : IRepository<T>
    {
        return Container.Resolve<TRepository>();
    }

(这里,PersistentObject< T>是提供ID和Equals支持的基类.)

因此,访问给定的存储库就是这种模式

NHibernateRepository.For<MyDomainType>().Save();

这样就可以使用了

MyDomainType.Repository.Save();

在给定类型具有专用存储库的情况下(即,需要比从IRepository< T>获得的更多),然后我创建从IRepository< T>派生的接口,这是从我的IRepository< T>继承的扩展实现.实现,并在域类型本身我使用new覆盖静态存储库属性

new public static IUserRepository Repository
    {
        get
        {
            return MyApplication.Repository.For<User,IUserRepository>();
        }
    }

(MyApplication [在真实产品中被称为不那么笨拙]是一个Facade类,负责通过Unity提供Repository实例,因此您不依赖于域类中特定的NHibernate存储库实现.)

这为我提供了通过Unity实现存储库实现的完全可插拔性,可以轻松访问代码中的存储库而无需跳过箍,以及透明的每线程ISession管理.

代码不仅仅是上面的代码(我已经简化了示例代码),但是你得到了一般的想法.

MyApplication.Repository.BeginUnitOfWork();
User user = User.Repository.FindByEmail("wibble@wobble.com");
user.FirstName = "Joe"; // change something
user.LastName = "Bloggs";
// you *can* call User.Repository.Save(user),but you don't need to,because...
MyApplication.Repository.EndUnitOfWork();
// ...causes session flush which saves the changes automatically

在我的Web应用程序中,我有每个请求的会话,因此分别在BeginRequest和EndRequest中调用BeginUnitOfWork和EndUnitOfWork.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读