简体   繁体   English

具有Ninject和EF Core的MVC 5,上下文在一个查询后引发异常

[英]MVC 5 with Ninject and EF Core, Context throws exception after one query

I am trying to use EF Core in our ASP.Net MVC 5 web application using Framework 4.6.1. 我正在尝试使用Framework 4.6.1在我们的ASP.Net MVC 5 Web应用程序中使用EF Core。 We are using Ninject for dependency injection. 我们正在使用Ninject进行依赖项注入。 I am injecting the Context in the DAL layer. 我在DAL层中注入上下文。 I am successful a performing a single query but the context throws the following exception when the next query is run 我成功执行了一个查询,但是运行下一个查询时上下文抛出以下异常

No database provider has been configured for this DbContext. 没有为此DbContext配置数据库提供程序。 A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. 可以通过重写DbContext.OnConfiguring方法或在应用程序服务提供程序上使用AddDbContext来配置提供程序。 If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext. 如果使用AddDbContext,则还应确保DbContext类型在其构造函数中接受DbContextOptions对象,并将其传递给DbContext的基本构造函数。

I have seen this error before but I am not really sure how it applies in my situation. 我之前曾见过此错误,但我不确定该如何在我的情况下使用。 What is it about my setup that is causing this error to be thrown? 我的设置是什么导致该错误引发的? Here is some code: 这是一些代码:

The Controller: 控制器:

public ActionResult GetEnrollmentWorkflows()
{
    var class1Entities = this._class1Service.GetAll().ToList();
    var class1EntityIds = class1Entities.Select(x => x.Class1EntityId).ToList(); // Works
    var class2Entity =
        this._class2EntityService
            .GetByClass1EntityIds(class1EntityIds).ToList(); // Fails with exception
    return PartialView("_somePartial", model);
}

The context binding: 上下文绑定:

kernel.Bind<Context.ContextTenant>().ToSelf().InTransientScope()
    .WithConstructorArgument("options",
        new DbContextOptionsBuilder<Tables.ContextTenant>()
    .UseSqlServer(ConfigurationManager.ConnectionStrings
        [EnvironmentConsts.DbConnectionTenant].ConnectionString)
    .Options);

The context: 上下文:

public ContextTenant(DbContextOptions<Tables.ContextTenant> options) : base(options)
{}

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    base.OnConfiguring(optionsBuilder);
}

The Ninject Modules: Ninject模块:

public class DalModule : NinjectModule
{
    public override void Load()
    {
        this.Kernel.Bind(x =>
            x.FromThisAssembly().SelectAllClasses().Join
                .FromAssemblyContaining<ISomeInterface>()
                .SelectAllInterfaces()
                .BindAllInterfaces().Configure(y => y.InTransientScope()));
    }
}



public class ServiceModule : NinjectModule
{
    public override void Load()
    {
        this.Kernel?.Load(new[] { new DalModule() });
        this.Kernel.Bind(x =>
            x.FromThisAssembly().SelectAllClasses().Join
                .FromAssemblyContaining<ISomeInterface>()
                .SelectAllInterfaces()
                .BindAllInterfaces().Configure(y => y.InTransientScope()));
    }
}

The DAL Classes DAL类

Class1: 第1类:

public class Class1Repository : IClass1Repository
{
    private ContextTenant ContextTenant { get; }

    public Class1Repository(ContextTenant contextTenant)
    {
        ContextTenant = contextTenant;
    }

    public IEnumerable<Class1Entity> GetAll()
    {
        return this.ContextTenant.Class1Entity.Select(x => x);
    }
}

Class 2: 第2类:

public class Class2Repository : IClass2Repository
{
    private readonly ContextTenant _contextTenant;

    public Class2Repository(ContextTenant contextTenant)
    {
        _contextTenant = contextTenant;
    }

    public IEnumerable<Class2Entity> GetByClass1EntityIds(
        IEnumerable<int> class1EntityIds)
    {
        return this._contextTenant.Class2Entity.Where(x =>
            class1EntityIds.Contains(x.Class1EntityId));
    }
}

The Services: 服务内容:

public class Class1Service : IClass1Service
{
    private readonly IClass1Repository _class1Repository;

    public Class1Service(IClass1Repository class1Repository)
    {
        _class1Repository = class1Repository;
    }

    public IEnumerable<Class1Entity> GetAll()
    {
        return this._class1Repository.GetAll();
    }
}

public class Class2Service : IClass2Service
{
    private readonly IClass2Repository _class2Repository;

    public Class2Service(IClass2Repository class2Repository)
    {
        _class2Repository = class2Repository;
    }

    public IEnumerable<Class2Entity> GetByClass1EntityIds(
        IEnumerable<int> class1EntityIds)
    {
        return this._class2Repository.GetByClass1EntityIds(class1EntityIds);
    }
}

Edit: Here is a little bit more code from the start up in case this would affect anything: 编辑:如果有什么影响的话,这里还有一些更多的代码:

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(NinjectWebCommon), "Stop")]
namespace MyApp
{
    public static class NinjectWebCommon
    {
        private static readonly Bootstrapper bootstrapper = new Bootstrapper();

        public static void Start()
        {
            DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
            DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
            bootstrapper.Initialize(CreateKernel);
        }

        public static void Stop()
        {
            bootstrapper.ShutDown();
        }

        private static IKernel CreateKernel()
        {
            // Bind the context
        }
    }
}

Based on what I am reading above I believe it is because you are using RequestScope. 基于以上内容,我相信这是因为您正在使用RequestScope。 The thing is that db context will dispose after each using and because you are still in the same request, when you call it again it has been disposed, but yet it serves that same instance. 事实是,db上下文将在每次使用后进行处理,并且由于您仍在同一个请求中,因此当您再次调用它时,它已经被处理了,但是它仍服务于同一实例。 Change it to Transient (or Transient equivalent with Ninject, meaning get new db context on every request) and it should fix the problem. 将其更改为Transient(或与Ninject等效的Transient,这意味着在每个请求上获取新的数据库上下文),它应该可以解决问题。

I had similar problems in the past that sometimes could be solved by changing 我过去有类似的问题,有时候可以通过更改来解决

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    base.OnConfiguring(optionsBuilder);
}

In

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (optionsBuilder.IsConfigured == false)
    { 
        base.OnConfiguring(optionsBuilder);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM