【问题标题】:NServiceBus and Entity Framework causes exception - The underlying provider failed on OpenNServiceBus 和实体框架导致异常 - 底层提供程序在打开时失败
【发布时间】:2016-04-30 07:42:34
【问题描述】:

我无法理解端点中的以下异常并对其进行故障排除。我在 SO 上看到了很多关于此错误的帖子,但毫无疑问反映了我们应用程序中的特定场景。

间歇性发生,我之前尝试通过增加实体框架的连接和命令超时来解决这个问题。

端点和数据库在同一台机器上运行。该错误不会经常发生,仅可能用于较大的更新或删除。

作为旁注,我经常在调试时得到“底层提供程序在打开时失败”。我一直认为这是因为我在断点上花费了太多时间,并且在我继续时连接已关闭。

我想问在 NServiceBus 端点中使用/注入实体框架 DbContext 的最佳实践是什么最好通过 NSB 的依赖注入来注入上下文吗? 像这样:

public class ConfigureDependencyInjection : INeedInitialization
{
    public void Customize( BusConfiguration configuration )
    {
        configuration.RegisterComponents( reg =>
        {
            reg.ConfigureComponent<MyDbContext>( DependencyLifecycle.InstancePerCall );
        } );
    }
}

或者我应该不使用它,而是根据需要实例化上下文:

using (var context = new MyDbContext()) { ... }

这里处理的消息是一条物理消息,非常直接——这就是我选择 DependencyLifecycle.InstancePerCall 的原因。

但是 DependencyLifecycle.InstancePerUnitOfWork 何时是使用实体框架时的正确选项?

如何才能更好地调试此错误?

这里是异常和堆栈:

The underlying provider failed on Open.
The operation is not valid for the state of the transaction.

at System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction, Guid promoterType)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Guid promoterType)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.PrepareConnection(DbConnection owningObject, DbConnectionInternal obj, Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.Open(DbConnection connection, DbInterceptionContext interceptionContext)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
--- End of inner exception stack trace ---
at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
at System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.Load(List`1 collection, MergeOption mergeOption)
at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.DeferredLoad()
at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.LoadProperty[TItem](TItem propertyValue, String relationshipName, String targetRoleName, Boolean mustBeNull, Object wrapperObject)
at System.Data.Entity.Core.Objects.Internal.LazyLoadBehavior.<>c__DisplayClass7`2.<GetInterceptorDelegate>b__1(TProxy proxy, TItem item)
at System.Data.Entity.DynamicProxies.JournalTransaction_4CAE8D09C8D2614F98562EAA87E63CE3B6D4E9A6DEC760505C0C7C7C42295ECE.get_TransactionItems()

这适用于 NSB 5.2.14,尽管早期版本显示相同的行为。

感谢您的帮助。

【问题讨论】:

    标签: c# .net entity-framework dependency-injection nservicebus


    【解决方案1】:

    John,当连接已经打开和关闭时也会出现此错误,也许这就是问题所在。但它似乎试图加入分布式事务并在那里失败。如果是在调试时,你要调试多长时间?可能是连接超时并重试打开关闭的连接?你的连接超时是多少?你用什么交通工具? MSDTC 开启了吗?你知道它什么时候开始失败吗?是不同的信息还是相同的信息?

    不确定你MyDbContext 的行为如何,但我的总是这样:

    public class MyDbContext : DbContext
    {
      public MyDbContext : base("MyConnectionString")
      {
      }
    }
    

    这样我可以确保它选择一个特定的连接字符串,并且我知道我不会忘记它,还有什么不会。

    【讨论】:

    • 是的,我的 DbContext 和你的完全一样。我的连接超时是 ;Connection Timeout=180 --- 我在调试时总是要快点,所以我没有得到错误。不过在生产中,我不知道。 MSDTC 是否必须打开,即使它是本地数据库?为什么它不会 100% 失败,而只有 3/100?感谢您的意见和想法。
    • 只有当您使用 SQL 作为持久性、传输和您自己的数据(由 EF 访问)在同一个数据库中,并且您的连接字符串都相同时,您才不会使用 MSDTC。当然,如果您的传输或持久性不支持事务。所以基本上,将 MSMQ + SQL Server 用于任何事情,使其成为分布式事务。事务管理器只能管理自己的资源,所以2个事务管理器就是MSDTC。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多