【问题标题】:Ninject, MVC5, EF6, Repository + UoWNinject、MVC5、EF6、存储库 + UoW
【发布时间】:2016-02-05 12:24:23
【问题描述】:

我遇到了两个问题,第一个是缩放并在负载测试时变得可见。

在负载下,事情很快(10 个并发或更少)失败并出现错误:

已经有一个打开的 DataReader 与此命令关联,必须先关闭。

或者

ExecuteReader 需要一个打开且可用的连接。连接的当前状态为打开。

堆栈跟踪每次都会引用一个存储库,例如:

Line 23:         public AboutViewDto GetAboutView()
Line 24:         {
Line 25:             var featured = UnitOfWork.FaqRepository
Line 26:                 .GetFeatured()

原始 NinjectDependencyResolver:

    public class NinjectDependencyResolver 
        : IDependencyResolver, System.Web.Mvc.IDependencyResolver
    {
        private readonly IKernel _kernel;

        public NinjectDependencyResolver() : this(new StandardKernel())
        {

        }

        public NinjectDependencyResolver(IKernel kernel)
        {
            _kernel = kernel;
            AddBindings(_kernel);
        }

        public IDependencyScope BeginScope()
        {
            return this;
        }

        public object GetService(Type serviceType)
        {
            return _kernel.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return _kernel.GetAll(serviceType);
        }

        public void Dispose()
        {
            // nothing?? 
        }

        private static void AddBindings(IBindingRoot kernel)
        {

            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

            kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InSingletonScope();
            kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InSingletonScope();

            kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InSingletonScope();
            kernel.Bind<IFaqRepository>().To<FaqRepository>().InSingletonScope();
            kernel.Bind<IListValueRepository>().To<ListValueRepository>().InSingletonScope();
            kernel.Bind<INoticeRepository>().To<NoticeRepository>().InSingletonScope();
            kernel.Bind<IOrganizationRepository>().To<OrganizationRepository>().InSingletonScope();
            kernel.Bind<ITagRepository>().To<TagRepository>().InSingletonScope();

            kernel.Bind<IAdminService>().To<AdminService>();
            kernel.Bind<IAutoMapperService>().To<AutoMapperService>();
            kernel.Bind<IHomeService>().To<HomeService>();
            kernel.Bind<IInfoService>().To<InfoService>();
            kernel.Bind<IMailService>().To<MailService>();
            kernel.Bind<INoticeService>().To<NoticeService>();
            kernel.Bind<IOrganizationService>().To<OrganizationService>();
            kernel.Bind<ISearchService>().To<SearchService>();

            kernel.Bind<IValidator<QuestionDto>>().To<QuestionDtoValidator>();
            kernel.Bind<IValidator<NoticeCommentDto>>().To<CommentDtoValidator>();
            kernel.Bind<IValidator<NoticeContactDto>>().To<NoticeContactDtoValidator>();
            kernel.Bind<IValidator<NoticeDto>>().To<NoticeDtoValidator>();
            kernel.Bind<IValidator<OrganizationDto>>().To<OrganizationDtoValidator>();

        }
    }
}

我预感到 InSingletonScope() 会导致问题,所以我将其更改为:

kernel.Bind&lt;IDataContext&gt;().To&lt;PublicCommentDbContext&gt;().InRequestScope();

并将所有其他 SingletonScopes 更改为 RequestScope。

进行该更改后,该站点可以处理 400 多个并发用户而没有任何故障,但是...

现在没有提交对数据库起作用。我可以通过控制器、服务、存储库和 DBContext 提交来跟踪调用,但插入或更新没有发生。

我将在此处发布每个项目的 sn-ps,希望有人能发现我们犯的愚蠢错误或提出改进建议。

片段如下:

活动,更新通知,所涉及的一切:

1) 忍者:

kernel.Bind<IDataContext>().To<PublicCommentDbContext>().InRequestScope();
kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>)).InRequestScope();
kernel.Bind<INoticeService>().To<NoticeService>();
 .. etc...

2) 控制器:

public sealed class NoticeController : BaseController
{
    public NoticeController(IAutoMapperService autoMapperService, INoticeService noticeService)
    {
        AutoMapperService = autoMapperService;
        NoticeService = noticeService;
    }
...

3) 通知服务

public class NoticeService : BaseService, INoticeService
{
    public NoticeService(
        IUnitOfWork unitOfWork, 
        IAutoMapperService autoMapperService,
        IValidator<NoticeDto> noticeDtoValidator)
        : base(unitOfWork)
    {
        AutoMapperService = autoMapperService;
        NoticeDtoValidator = noticeDtoValidator;
    }

4) 工作单元

public class UnitOfWork : IUnitOfWork
{
    private IDataContext _dataContext;
    private bool _disposed;
    private ObjectContext _objectContext;
    private DbTransaction _transaction;

    public UnitOfWork(
        IDataContext dataContext,
        INoticeRepository noticeRepository)
    {
        _dataContext = dataContext;
        NoticeRepository = noticeRepository;
    }

5) 通知库

public class NoticeRepository : Repository<Notice>, INoticeRepository
{
   public NoticeRepository(IDataContext context) : base(context)
   {

   }
...

6) 控制器动作

    public ActionResult Create(NoticeViewModel notice)
    {
        notice.TypeId = Convert.ToInt32(NoticeType.ManuallyEnteredDocument);
        var newNotice = AutoMapperService.Map<NoticeViewModel, NoticeDto>(notice);
        NoticeService.Create(newNotice);
        return RedirectToAction("Details", new { name = notice.Arc });
    }

7) NoticeService.Create(new):

    public void Create(NoticeDto notice)
    {
        NoticeDtoValidator.ValidateAndThrow(notice);
        var newNotice = AutoMapperService.Map<NoticeDto, Notice>(notice);
        UnitOfWork.NoticeRepository.Add(newNotice);
        UnitOfWork.SaveChanges();
    }

8) 通用存储库 Add():

    public virtual void Add(TEntity entity)
    {
        entity.ObjectState = ObjectState.Added;
        _dbSet.Attach(entity);
        _context.SyncObjectState(entity);
    }

9) UnitOfWork SaveChanges():

    public int SaveChanges()
    {
        return _dataContext.SaveChanges();
    }

当我逐步执行此操作时,#8 中附加的实体看起来正确,状态已添加,当调用保存更改时,基本 SaveChanges() 中没有记录任何更改:

    public override int SaveChanges()
    {
        SyncObjectsStatePreCommit();
        base.ChangeTracker.DetectChanges();
        var result = base.ChangeTracker.HasChanges();
        var changes = base.SaveChanges();

这里的结果是假的

怎么可能?除了 EF6 上下文之上的抽象地狱和 UoW/Repos 之外,我还缺少什么(我继承了这个)。

有人在外面看到了什么愚蠢的东西吗?

没有错误,没有异常,插入就不会发生。

【问题讨论】:

  • 我已经开始淘汰 Ninject 并将进行一些测试。

标签: c# asp.net-mvc entity-framework ninject repository-pattern


【解决方案1】:

问题解决了,问题在于 Ninject 将不同的上下文注入到我们的存储库中。

我们找到了两种解决方法:

选项 1) 在我们的工作单元中,我们创建了一个额外的构造函数,它只接收一个 dbcontext 并创建新的存储库,将 dbcontext 传递给它们。我们也离开了旧的构造函数,以便我们可以注入 repos 进行测试。这很有效,而且是一个微不足道的改变。

选项 2) 移除 Ninject 并重载每个控制器的构造函数,手动创建项目。由于这个项目很小,我们只需要触摸 6 个控制器就可以正常工作,每个控制器只需 4 行新代码。我们也保留了旧的构造函数,以便注入服务进行测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-16
    • 1970-01-01
    • 2019-09-04
    • 2011-05-21
    • 1970-01-01
    相关资源
    最近更新 更多