直接注入存储库时调用Dispose与Kernel.Get的区别

时间:2014-08-27 07:10:15

标签: c# dependency-injection ninject idisposable

我有一个包含多个存储库的服务(通过ninject绑定):

Bind<IRepository<User>>().To<Repository<User>>().InRequestScope();

由于服务在构造函数中注入了太多依赖项,因此我决定使用RepositoryProvider

public class RepositoryProvider : IRepositoryProvider
{
    private readonly Func<Type, object> factory;

    public RepositoryProvider(Func<Type, object> factory)
    {
        if (factory == null)
        {
            throw new ArgumentNullException("factory");
        }

        this.factory = factory;
    }

    public IRepository<T> GetRepository<T>() where T : class
    {
        Type type = typeof(T);
        object repository = factory(type);
        if (repository != null)
        {
            return (IRepository<T>)repository;
        }

        string message = string.Format(CultureInfo.InvariantCulture, "No repository found for {0}", type.Name);
        throw new NotImplementedException(message);
    }
}

通过Ninject注册存储库工厂:

Func<Type, object> repositoryFactory = type =>
        {
            Type repositoryType = typeof(IRepository<>).MakeGenericType(type);
            return Kernel.Get(repositoryType);
        };

这提供了一个通用存储库的实例:

public class Repository<T> : IRepository<T>, IDisposable where T : class
{
    private IEntities context;

    public Repository(IEntities context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        this.context = context;
    }

    public IQueryable<T> GetAll() 
    {
        return context.GetDbSet<T>();
    }

    #region IDisposable
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    public virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            context.Dispose();
            context = null;
        }
    }
    #endregion
}

现在,当我直接在服务中注入存储库时,我看到在请求之后立即调用Dispose()方法(当我设置断点时)。但是当我使用提供程序时,我根本看不到Dispose()

这可能是什么原因?我是否已完成所有设置以确保ninject调用Dispose()? 我看到其他答案提到“OncePerWebRequest”模块,但似乎无法找到任何关于此的文档,也不知道这是否有必要。

1 个答案:

答案 0 :(得分:1)

当您从ctor注入更改为工厂创建时,您更改了&#34; time&#34;实例是createad。由于InRequestScope()以前有效,我建议在HttpContext.Current无效/为空的位置创建工厂创建的实例。

请注意,从ctor注入更改为工厂创建,您已经打开了一个新问题:您现在正在使用服务位置,并且您的对象图不是(必然)从根目录创建的走。还see Mark Seeman's blog post on service locator

修复&#34;所有&#34;一次性问题我建议稍微调整一下存储库。与IRepository<T>之类的方法T GetAll()不同,为什么不将其更改为IRepositoryT GetAll<T>()等方法。这样,您只需要一个存储库实例:

public class Repository : IRepository, IDisposable
{
    private IEntities context;

    public Repository(IEntities context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        this.context = context;
    }

    public IQueryable<T> GetAll<T>() 
        where T : class
    {
        return context.GetDbSet<T>();
    }

    #region IDisposable
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    public virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            context.Dispose();
            context = null;
        }
    }
    #endregion
}