在Azure函数中使用Ninject确定实体框架

时间:2017-12-24 18:26:44

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

我在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   key,TValue value,Boolean add)
  在   System.Data.Entity.Core.Objects.ObjectStateManager.AddStateManagerTypeMetadata(EntitySet的   entitySet,ObjectTypeMapping mapping)
   在   System.Data.Entity.Core.Objects.ObjectStateManager.GetOrAddStateManagerTypeMetadata(类型   entityType,EntitySet entitySet)
  在   System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper   wrappedObject,EntityKey passedKey,EntitySet entitySet,String   argumentName,Boolean isAdded)
  在   System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly [TEntity](Func键' 2   constructEntityDelegate,EntityKey entityKey,EntitySet entitySet)
  在lambda_method(Closure,Shaper)
  在   System.Data.Entity.Core.Common.Internal.Materialization.Coordinator' 1.ReadNextElement(整形器   整形)
  在   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:\一个\ 1 \ S \ MyApp的\ MyApp.DAO \实现\ LoanRepository.cs:线   50个
  at MyApp.DAO.Implementations.LoanRepository.Get(String   loanGuid)in   d:\一个\ 1 \ S \ MyApp的\ MyApp的\实现\ LoanRepository.cs:线   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()at   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()at   MyApp.DAO.Implementations.PromotionRepository.getAllActivePromotions(的Int32   LoanID)in   d:\一个\ 1 \ S \ MyApp的\ MyApp.DAO \实现\ PromotionRepository.cs:线   56 at MyApp.DAO.Implementations.LoanRepository.Get(Int32   loanId)in   d:\一个\ 1 \ S \ MyApp的\ MyApp.DAO \实现\ LoanRepository.cs:线   204在   MyApp.DAO.Implementations.LoanRepository.Get(字符串   loanGuid)in   d:\一个\ 1 \ S \ MyApp的\ MyApp.DAO \实现\ LoanRepository.cs:线   0点   MyApp.BL.Los.MyManager.d__22.MoveNext()   在   d:\一个\ 1 \ S \ MyApp的\ MyApp.BL.Los \ MyManager.cs:线   63

Ninject配置

 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
   }
}

2 个答案:

答案 0 :(得分:3)

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

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&#39; 1.SimpleEnumerator.Dispose()在System.Data.Entity.Internal。 LazyEnumerator `1.Dispose()

我认为在使用EF时会从操作中抛出错误。在部署DbContext之前,您需要确保访问延迟加载的导航属性。这是一个类似的issue,你可以参考它。通常,您需要检查代码并尝试根据异常的完整StackTrace查找导致此问题的特定代码行。或者,您可以使用有关错误的详细信息以及您用于缩小此问题的代码来更新您的问题。

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

答案 1 :(得分:1)

我猜你在using语句之外调用了上下文。使用内核创建的上下文对象的生命周期仅适用于using语句的生命周期。但是,在您提供的示例中,您真的不需要DI。如果要在函数内实例化内核然后从中访问上下文,那么不要只创建上下文。如果你设置了这个,那么你需要传递Kernal作为函数的参数。