C# 存储库模式工作单元依赖项注入Ninject

C# 存储库模式工作单元依赖项注入Ninject,c#,dependency-injection,ninject,repository-pattern,unit-of-work,C#,Dependency Injection,Ninject,Repository Pattern,Unit Of Work,我在体系结构中使用存储库、工作单元和依赖注入模式 我的分层: 核心 数据层 业务层 服务层 我的结构有点不对劲,在上面提到的工薪阶层中 public class UnitOfWork:IUnitOfWork { private readonly IDataContext _context; private IKullaniciDal _kullaniciDal; private IKategoriDal _kategoriDal; private IUrun

我在体系结构中使用存储库、工作单元和依赖注入模式 我的分层:

核心

数据层

业务层

服务层

我的结构有点不对劲,在上面提到的工薪阶层中

   public class UnitOfWork:IUnitOfWork
{
    private readonly IDataContext _context;
    private IKullaniciDal _kullaniciDal;
    private IKategoriDal _kategoriDal;
    private IUrunDal _urunDal;
    public UnitOfWork(IDataContext context)
    {
        _context = context;
    }

    public IKategoriDal KategoriDal => _kategoriDal ?? (_kategoriDal = new KategoriDal(_context));

    public IKullaniciDal KullaniciDal => _kullaniciDal ?? (_kullaniciDal =  new KullaniciDal(_context));

    public IUrunDal UrunDal => _urunDal ?? (_urunDal = new UrunDal(_context));

    public void SaveChanges()
    {
        _context.SaveChanges();
    }
}
在这里,我想注入数据访问层,比如kullaniciDAL

搜索了很多,我看到了一些生成存储库的示例,但是我不想直接从业务访问存储库实例,我想访问KullaniciDal类的实例 这是KullaniciDal的代码

 public interface IKullaniciDal : IRepositoryEntityFramework<Kullanici>
{
}

public class KullaniciDal : RepositoryEntityFramework<Kullanici>, IKullaniciDal
{
    public KullaniciDal(IDataContext dbContextBase) : base(dbContextBase)
   {
   }
}
公共接口ikullanicial:IRepositoryEntityFramework
{
}
公共类KullaniciDal:RepositoryEntityFramework,IKullaniciDal
{
公共KullaniciDal(IDataContext dbContextBase):基(dbContextBase)
{
}
}
我想为数据访问层编写一些额外的函数,特别是其中的一些函数,并希望将实例用作工作类单元的一部分

我如何注入Dal类?
请注意,我将上下文对象传递给每个dal类

我在这里看到了几个问题

首先,您的UoW正在更新DAL本身,而不是由DI注入。如果你要走DI路线,最好让DI注入一切,让它自己管理对象的范围等。作为一种一般规则,如果您发现自己使用NeW()具有基础结构类,请后退一步并考虑注入它。

public class UnitOfWork:IUnitOfWork
{
    private readonly IDataContext _context;
    public UnitOfWork(IDataContext context,IKullaniciDal kullaniciDal,IKategoriDal kategoriDal, IUrunDal urunDal)
    {
        KullaniciDal = kullaniciDal;
        KategoriDal = kategoriDal;
        UrunDal = urunDal;
        _context = context;
    }

    public IKategoriDal KategoriDal{get;private set;}

    public IKullaniciDal KullaniciDal{get;private set;}

    public IUrunDal UrunDal{get;private set;}

    public void SaveChanges()
    {
        _context.SaveChanges();
    }
}
下一个问题更像是一个设计问题。为什么UoW需要所有这些DAL?我自己也觉得这很奇怪

如果我要实现一个需要控制UoW和DAL的业务层,我只需要将它们注入业务层

public class FooBLL
{
    private IKullanicDal _kullanicDal;
    private IUnitOfWork _unitOfWork;
    public FooBLL(IKullanicDal kullanicDal,IUnitOfWork unitOfWork)
    {
        _kullanicDal = kullanicDal;
        _unitOfWork = unitOfWork;
    }

    public void FooBusinessMethod()
    {
      _unitOfWork.Begin();
      //do something with dal
      //_unitOfWork.Commit etc
    }

}
的确,在使用诸如EF之类的ORM时,存储库/dll和工作单元都需要上下文,但它们是独立的模式。我会允许您的DI容器适当地定义您的上下文、UoW、BLL等,您不必担心传递依赖项,让容器为您完成工作


这也有其他坚实的设计优势。考虑一下,如果你正在执行一个HTTP过滤器,自动提交你的UWO与HTTP会话。过滤器只需要知道IUnitOfWork方法commit、rollback等。它应该依赖于最小的接口,而不需要知道DAL。

我找到了另一种解决方案,可以在需要时动态创建存储库。 它还支持多个数据上下文,还有一点是IUnitOfWork接口继承了IDisposable。该代码适用于EF Core v2.0。以下是所有UnitOfWork.cs类代码:

public class UnitOfWork<TContext> : IUnitOfWork<TContext> where TContext : DbContext
{
    private Dictionary<string, dynamic> _repositories;
    private DbContext _context;

    public UnitOfWork(TContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public IRepository<TEntity> Repository<TEntity>() where TEntity : class, IEntity, new()
    {
        if (_repositories == null)
        {
            _repositories = new Dictionary<string, dynamic>();
        }
        var type = typeof(TEntity).Name;
        if (_repositories.ContainsKey(type))
        {
            return (IRepository<TEntity>)_repositories[type];
        }
        _repositories.Add(type, Activator.CreateInstance(typeof(RepositoryEntityFramework<TEntity>), _context));
        return _repositories[type];
    }

    public void SaveChanges()
    {
        _context.SaveChanges();
    }

    public void BeginTransaction(System.Data.IsolationLevel isolationLevel = System.Data.IsolationLevel.ReadCommitted)
    {
        _context.Database.BeginTransaction();
    }

    public bool Commit()
    {
        _context.Database.CommitTransaction();
        return true;
    }

    public void Rollback()
    {
        _context.Database.RollbackTransaction();
    }

    /// <inheritdoc />
    /// <summary>
    /// Disposes the current object
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Disposes all external resources.
    /// </summary>
    /// <param name="disposing">The dispose indicator.</param>
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_context != null)
            {
                _context.Dispose();
                _context = null;
            }
        }
    }
}
公共类UnitOfWork:IUnitOfWork,其中TContext:DbContext
{
私人词典库;
私有DbContext _context;
公共工作单元(TContext上下文)
{
_context=context??抛出新ArgumentNullException(nameof(context));
}
公共IRepository存储库(),其中tenty:class、ienty、new()
{
如果(_==null)
{
_存储库=新字典();
}
var type=typeof(tenty).Name;
if(_repositories.ContainsKey(类型))
{
返回(IRepository)_存储库[类型];
}
_Add(type,Activator.CreateInstance(typeof(RepositoryEntityFramework),_context));
返回_存储库[类型];
}
公共void SaveChanges()
{
_SaveChanges();
}
public void BeginTransaction(System.Data.IsolationLevel IsolationLevel=System.Data.IsolationLevel.ReadCommitted)
{
_context.Database.BeginTransaction();
}
公共boolcommit()
{
_context.Database.CommitTransaction();
返回true;
}
公共无效回滚()
{
_context.Database.RollbackTransaction();
}
/// 
/// 
///处理当前对象
/// 
公共空间处置()
{
处置(真实);
总干事(本);
}
/// 
///处理所有外部资源。
/// 
///dispose指示灯。
私有无效处置(bool处置)
{
如果(处置)
{
如果(_context!=null)
{
_context.Dispose();
_上下文=空;
}
}
}
}

我尝试了您提供的方法,但我有一个问题,即工作单元中的上下文实例和dal中的实例不一样。我在RequestScope()中使用ninject Bind().To();我在哪里wrong@OkanSARICA这一定是ninject配置中的一个范围问题,请也发布该代码。我使用的是ninject.Web.Common nuget软件包,我卸载了它并安装了ninject.Mvc3,问题解决了,很有趣,很高兴你解决了。让那个容器为你做范围界定。