Ninject设置为使用NHibernate一般存储库 [英] Ninject setup for general repository using Nhibernate

查看:271
本文介绍了Ninject设置为使用NHibernate一般存储库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发使用NHibernate和通用存储库的.NET Web API应用程序。现在,我试图用Ninject正确设​​置依赖注入。不过,我有一些问题,我目前的配置:偶尔我的NHibernate的ISession(以下UnitOfWork.cs)对象为null或使该下降到DAL,并试图从数据库中提取数据的请求时已经关闭。

I'm developing a .NET Web API application using Nhibernate and a generic repository. Now I'm trying to correctly setup dependency injection using Ninject. However, I have some problems with my current configuration: occasionally my NHibernate ISession (in UnitOfWork.cs below) object is either null or already closed when making a request that goes down to the DAL and tries to fetch data from the database.

我一直无法弄清楚究竟为什么发生这种情况或什么是错在我的code。我以为我的Ninject作用域/绑定在某种程度上不正确的,但不能让它开始工作。

I have not been able to figure out exactly why this happens or what is wrong in my code. I thought my Ninject scoping/binding was somehow incorrect, but cannot get it to work.

这是我目前的执行情况(我已经剥夺无关code,减少code的显示的金额):

This is my current implementation (I have stripped away irrelevant code to reduce the amount of code displayed):

NinjectWebCommon.cs

private static void RegisterServices(IKernel kernel)
{
   UnitOfWorkFactory uow = new UnitOfWorkFactory(
      ConfigurationManager.ConnectionStrings["foo"].ConnectionString,
      Assembly.GetExecutingAssembly());

   kernel.Bind<IUnitOfWorkFactory>().ToConstant(uow).InSingletonScope();
   kernel.Bind<IUnitOfWork>().ToMethod(f => f.Kernel.Get<IUnitOfWorkFactory().BeginUnitOfWork()).InRequestScope();

   // Services
   kernel.Bind<ICustomerService>().To<CustomerService>().InRequestScope();

   // Repositories
   kernel.Bind(typeof(IRepository<,>)).To(typeof(Repository<,>)).InRequestScope();

   // Used for Basic Auth (uses customer Service)
   kernel.Bind<IPrincipalProvider>().To<MyPrincipalProvider>().InRequestScope();
}

IUnitOfWorkFactory.cs

public interface IUnitOfWorkFactory : IDisposable
{
    IUnitOfWork BeginUnitOfWork();
    void EndUnitOfWork(IUnitOfWork unitOfWork);
}

UnitOfWorkFactory.cs

public class UnitOfWorkFactory : IUnitOfWorkFactory
{
    public UnitOfWorkFactory(string connectionString, Assembly assembly)
    {
        var rawCfg = new Configuration();
        rawCfg.SetNamingStrategy(new MsSql2005NamingStrategy());
        var cfg = Fluently
            .Configure(rawCfg)                .Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.ConnectionString(connectionString))
            .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()));

        Configuration = cfg.BuildConfiguration();
        SessionFactory = Configuration.BuildSessionFactory();
    }

    protected ISessionFactory SessionFactory { get; private set; }

    protected Configuration Configuration { get; private set; }

    public IUnitOfWork BeginUnitOfWork()
    {
        return new UnitOfWork(this.SessionFactory.OpenSession());
    }

    public void EndUnitOfWork(IUnitOfWork unitOfWork)
    {
        var nhUnitOfWork = unitOfWork as UnitOfWork;
        if (unitOfWork != null)
        {
            unitOfWork.Dispose();
            unitOfWork = null;
        }
    }

    public void Dispose()
    {
        if (this.SessionFactory != null)
        {
            (this.SessionFactory as IDisposable).Dispose();
            this.SessionFactory = null;
            this.Configuration = null;
        }
    }
}

IUnitOfWork.cs

public interface IUnitOfWork : IDisposable
{
    TEntity GetSingle<TEntity>(Expression<Func<TEntity, bool>> expression) where   TEntity : class;
}

UnitOfWork.cs

public class UnitOfWork : IUnitOfWork
{
   public UnitOfWork(NHiberante.ISession session)
   {
      if (session == null)
      {
         throw new ArgumentNullException("session");
      }
      this.Session = session;
   }

   public NHiberante.ISession Session { get; private set; }

   private IQueryable<TEntity> Set<TEntity>() where  TEntity : class
   {
      return Session.Query<TEntity>();
   }

   public TEntity GetSingle<TEntity>(Expression<Func<TEntity, bool>> expression)  where TEntity : class
   {
      return Set<TEntity>().SingleOrDefault(expression);
   }

   public void Dispose()
   {
      if ( this.Session != null )
      {
         (this.Session as IDisposable).Dispose();
         this.Session = null;
      }
   }
}

IRepository.cs

public interface IRepository<TEntity, TPrimaryKey> where TEntity : class
{
    TEntity GetSingle(Expression<Func<TEntity, bool>> expression);
}

Repository.cs

public class Repository<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : class
{
   public Repository(IUnitOfWork unitOfWork)
   {
      if (unitOfWork == null)
      {
         throw new ArgumentNullException("unitOfWork");
      }
      this.UnitOfWork = unitOfWork;
   }

   protected IUnitOfWork UnitOfWork { get; private set; }

   public virtual TEntity GetSingle(Expression<Func<TEntity, bool>> expression)
   {
      return UnitOfWork.GetSingle(expression);
   }
}

ICustomerService.cs

public interface ICustomerService
{
    Customer GetCustomer(string id);
}

的CustomerService

public class CustomerService : ICustomerService
{
    private readonly IRepository<Customer, string> _customerRepo;

    public CustomerService(IRepository<Customer, string> customerRepo)
    {
        _customerRepo = customerRepo;
    }

    public Customer GetCustomer(string id)
    {
        return _customerRepo.GetSingle(l => l.ID == id);
    }
}

CustomerController.cs

public class CustomerController : ApiController
{
    private ICustomerService _customerService;

    public CustomerController(ICustomerService customerService)
    {
        _customerService = customerService;
    }

    public string Get(string id)
    {
        var customer = _customerService.GetCustomer(id);
        return customer.Name;
    }
}

要总结的话:我做一个简单的GetCustomer请求。该CustomerController注射用的CustomerService实例。所述的CustomerService然后用库实例注入,并在库本身带有的UnitOfWork实现(这是由该方法BeginUnitOfWork()中UnitOfWorkFactory类创建)注入。另外值得一提的是,该请求首先被验证委托处理程序拦截(基本身份验证)。该处理器还使用的CustomerService。

To summarize in words: I make a simple GetCustomer request. The CustomerController is injected with a CustomerService instance. The CustomerService is then injected with a Repository instance, and the repository itself in injected with a UnitOfWork implementation (which is created by the method BeginUnitOfWork() in UnitOfWorkFactory class). Also worth mentioning is that the request is first intercepted by an authentication delegating handler (for basic authentication). This handler also uses the CustomerService.

在发出请求的API,(通过REST客户端,或卷曲或其他)这个最初的作品,但每一个现在,然后(或在以后的后续请求),我想,当得到一个错误倒在数据层访问的ISession对象(即NULL),我必须重新启动服务器让它再次合作。

When making requests to the API, (through a REST client or cURL or whatever) this initially works, but every now and then (or at some later subsequent request), I get an error down in the data layer when trying to access the ISession object (being NULL), and I must restart the server to get it working again.

我错过了一些东西明显?任何人都可以解释如何解决这个问题?谢谢!

Have I missed something obvious? Can anyone explain how to solve this? Thanks!

更新

我一直在调试这更进一步,发现我的UnitOfWork在每个请求正确实例化,从而获得一个新的ISession。但在某些情况下,UOW的Dispose() - 方法(根据堆栈跟踪由于一些NHibernate的缓存/修剪)触发两次。这就是为什么内部会话对象为null。一旦此异常被触发,在所有后续请求,Ninject明显发现的UnitOfWork的一个已经存在的情况下,这个空会话。 :/

I have been debugging this further and found out that my UnitOfWork is properly instantiated at every request and thus getting a new ISession. But in some cases the UoW Dispose()-method is triggered twice (due to some NHibernate caching/pruning according to the stack trace). That's why the internal session object is null. Once this exception is triggered, in all subsequent requests, Ninject obviously finds an already existing instance of UnitOfWork, with this null-session. :/

推荐答案

的Isession 对象不是由ninject而是由NH样品中进行管理。因此,你的 IUnitOfWork 可以比NH管理会话活得更长。无论是与Ninject管理一切或使用相应的会话环境。问题根源是在 BeginUnitOfWork ,你newing你的工作单元,并使用 SessionFactory.OpenSession()

The ISession object is not managed by ninject but by NH in your sample. Therefore your IUnitOfWork can live longer than the session managed by NH. Either manage everything with Ninject or use the appropriate session context. The problem root cause is in BeginUnitOfWork where you newing up your unit of work and use SessionFactory.OpenSession().

这篇关于Ninject设置为使用NHibernate一般存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆