【问题标题】:Scoping Entity Framework using Ninject in Azure Functions在 Azure Functions 中使用 Ninject 确定实体框架的范围
【发布时间】:2018-06-06 09:10:43
【问题描述】:

我在 Azure 函数中使用 Ninject 确定实体框架的范围时遇到了一些问题。

我不断收到已处置的随机对象和内部 EF 错误,如下所示,这使我相信 DbContext 正在线程之间共享:

我不确定这是否范围错误,或者我是否只需要在每个应用程序域中调用一次 _kernal.Load()。任何见解将不胜感激。

An item with the same key has already been added.

在 System.ThrowHelper.ThrowArgumentException(ExceptionResource 资源)在 System.Collections.Generic.Dictionary'2.Insert(TKey 键,TValue 值,布尔加)
在 System.Data.Entity.Core.Objects.ObjectStateManager.AddStateManagerTypeMetadata(EntitySet entitySet、ObjectTypeMapping映射)
在 System.Data.Entity.Core.Objects.ObjectStateManager.GetOrAddStateManagerTypeMetadata(类型 entityType, EntitySet entitySet)
在 System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper WrappedObject, EntityKey passKey, EntitySet entitySet, String 参数名称,布尔值已添加)
在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func'2 构造EntityDelegate, EntityKey entityKey, EntitySet entitySet)
在 lambda_method(闭包,Shaper)
在 System.Data.Entity.Core.Common.Internal.Materialization.Coordinator'1.ReadNextElement(Shaper 整形器)
在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.RowNestedResultEnumerator.MaterializeRow() 在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.RowNestedResultEnumerator.MoveNext() 在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.ObjectQueryNestedEnumerator.TryReadToNextElement() 在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.ObjectQueryNestedEnumerator.MoveNext() 在 System.Data.Entity.Internal.LazyEnumerator'1.MoveNext()
在 System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable'1 源)
在 System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.b__1[TResult](IEnumerable'1 序列)
在 System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.ExecuteSingle[TResult](IEnumerable'1 查询、表达式 queryRoot)
在 System.Data.Entity.Core.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute[TResult](表达式 表达)
在 System.Data.Entity.Internal.Linq.DbQueryProvider.Execute[TResult](表达式 表达)
在 System.Linq.Queryable.FirstOrDefault[TSource](IQueryable'1 源, 表达式`1 谓词)
在 MyApp.DAO.Implementations.LoanRepository.Get(Int32 loanId) 在 d:\a\1\s\MyApp\MyApp.DAO\Implementations\LoanRepository.cs:line 50
在 MyApp.DAO.Implementations.LoanRepository.Get(字符串 贷款指南)在 d:\a\1\s\MyApp\MyApp\Implementations\LoanRepository.cs:line 0
在 MyApp.BL.Los.MyManager.d__22.MoveNext()

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

在 System.Data.Entity.Core.Objects.ObjectContext.ReleaseConnection() 在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.Finally() 在 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.SimpleEnumerator.Dispose() 在 System.Data.Entity.Internal.LazyEnumerator`1.Dispose() 在 MyApp.DAO.Implementations.PromotionRepository.getAllActivePromotions(Int32 LoanID) 在 d:\a\1\s\MyApp\MyApp.DAO\Implementations\PromotionRepository.cs:line 56 在 MyApp.DAO.Implementations.LoanRepository.Get(Int32 贷款ID)在 d:\a\1\s\MyApp\MyApp.DAO\Implementations\LoanRepository.cs:line 204 在 MyApp.DAO.Implementations.LoanRepository.Get(字符串 贷款指南)在 d:\a\1\s\MyApp\MyApp.DAO\Implementations\LoanRepository.cs:line 0 在 MyApp.BL.Los.MyManager.d__22.MoveNext() 在 d:\a\1\s\MyApp\MyApp.BL.Los\MyManager.cs:line 63

注入配置

 public class NinjectBindings : NinjectModule
    {
        public override void Load()
        {
            Bind<MyDBContext>().ToSelf().InSingletonScope().WithConstructorArgument("connectionString", "name=MyDB");
        }
    }

Azure 函数

[FunctionName("ProcessData")]
public static async Task ProcessData([QueueTrigger("myqueue", Connection = "AzureWebJobsStorage")]string message, int dequeueCount, ILogger log, ExecutionContext context)
{
   using (StandardKernel _kernal = new StandardKernel())
   {
       _kernal.Load(Assembly.GetExecutingAssembly());
    // do work
   }
}

【问题讨论】:

  • 您不知道上下文是否被共享并且您正在使用InSingletonScope?你知道什么是单例吗?
  • 我当然知道单例是什么。 Ninject 声明:“当内核被释放时,单例实例被释放”,您可以清楚地看到,这就是我正在做的事情
  • 您是否正确等待您使用中的所有调用?你能提供完整的堆栈跟踪吗?
  • 是的,所有电话都应该是正确的awaited。此外,所有 EF 代码都是同步调用。
  • EF 不是线程安全的,为每个线程创建一个上下文:stackoverflow.com/questions/4455634/…

标签: c# entity-framework azure ninject azure-functions


【解决方案1】:

根据您的描述,我使用了您的代码,发现以下代码可以按预期工作。

using (StandardKernel _kernal = new StandardKernel())
{
    _kernal.Load(Assembly.GetExecutingAssembly());

    // do work
    BruceDbContext ctx = _kernal.Get<BruceDbContext>();
    var todoitem = ctx.TodoItems.FirstOrDefault();
    log.Info(JsonConvert.SerializeObject(todoitem));
}

ObjectContext 实例已被释放,不能再用于需要连接的操作。 System.Data.Entity.Core.Common.Internal.Materialization.Shaper'1.SimpleEnumerator.Dispose() 在 System.Data.Entity.Internal.LazyEnumerator`1.Dispose()

我假设错误是在使用 EF 时从您的操作中引发的。您需要确保在处置 DbContext 之前访问延迟加载导航属性。这里有一个类似的issue,你可以参考一下。一般来说,您需要检查您的代码并尝试根据异常的完整 StackTrace 找到导致此问题的特定代码行。或者,您可以更新您的问题,提供有关错误的更多详细信息以及您用于我们缩小此问题的代码。

此外,Azure Functions 不支持类似于 webjobs 方式的 DI。另外,我找到了 github issue。此外,您可以关注Proper Dependency injection in Azure Functions on function level with scoped services!Dependency injection in Azure Functions on function level

【讨论】:

  • EF代码是已经使用了一段时间的现有代码,没有类似的错误。我相信这个错误是由于 Azure Functions 中的 ninject 配置错误而发生的。我确实看过有关 DI 不受支持的帖子,但想看看是否有任何解决方法 - 因为我的类都是用构造注入设计的,我不想修改它们
  • @CamBruce,如果您的代码已经使用了很长时间,那么这些麻烦是什么时候开始的?
  • 当现有的数据访问组件用于 Azure Function 的上下文中时,问题就开始了,而不是以前在 Web 应用程序中使用它们
【解决方案2】:

我猜你在 using 语句之外调用了上下文。您使用内核创建的上下文对象的生命周期仅适用于 using 语句的生命周期。但是,在您提供的示例中,您确实不需要 DI。如果您在函数内部实例化内核,然后从中访问上下文,为什么不直接创建上下文。如果您对此进行了设置,则需要将内核作为函数的参数传递。

【讨论】:

    猜你喜欢
    • 2017-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多