"句柄无效"打开SqlConnection时出错

时间:2015-07-01 17:32:05

标签: c# asp.net .net sql-server

此错误已经开始偶尔发生并且莫名其妙,尤其是在连接到会话状态数据库时。这是错误:

   Exception type: COMException 
    Exception message: The handle is invalid. (Exception from HRESULT: 0x80070006 (E_HANDLE))
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   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()

在Windows事件查看器中有时会出现可能相关的错误:

Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Threading.SemaphoreFullException
Stack:
   at System.Threading.Semaphore.Release(Int32)
   at System.Data.ProviderBase.DbConnectionPool.CleanupCallback(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.TimerQueueTimer.CallCallback()
   at System.Threading.TimerQueueTimer.Fire()
   at System.Threading.TimerQueue.FireNextTimers()

编辑:另一种例外情况如下:

Exception Type: System.ComponentModel.Win32Exception
Error message: An operation was attempted on something that is not a socket
No Stack Trace Available
Exception Type: System.Data.SqlClient.SqlException
Error message: A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An operation was attempted on something that is not a socket.)
at System.Data.SqlClient.TdsParser.TdsExecuteRPC(_SqlRPC[] rpcArray, Int32 timeout, Boolean inSchema, SqlNotificationRequest notificationRequest, TdsParserStateObject stateObj, Boolean isCommandProc, Boolean sync, TaskCompletionSource`1 completion, Int32 startRpc, Int32 startParam)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
at System.Web.SessionState.SqlSessionStateStore.SqlExecuteReaderWithRetry(SqlCommand cmd, CommandBehavior cmdBehavior)
Exception Type: System.Web.HttpException
Error message: Unable to connect to SQL Server session database.
at System.Web.SessionState.SqlSessionStateStore.SqlExecuteReaderWithRetry(SqlCommand cmd, CommandBehavior cmdBehavior)
at System.Web.SessionState.SqlSessionStateStore.DoGet(HttpContext context, String id, Boolean getExclusive, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags)
at System.Web.SessionState.SqlSessionStateStore.GetItem(HttpContext context, String id, Boolean& locked, TimeSpan& lockAge, Object& lockId, SessionStateActions& actionFlags)
at System.Web.SessionState.SessionStateModule.GetSessionStateItem()
at System.Web.SessionState.SessionStateModule.BeginAcquireState(Object source, EventArgs e, AsyncCallback cb, Object extraData)
at System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

任何人都可以建议:

  1. 这是什么意思?
  2. 导致这种情况的原因(这是一个非常稳定地运行了很长时间的应用程序,在此之前没有发生重大的基础设施变化)?
  3. 可以采取哪些措施来解决它?

4 个答案:

答案 0 :(得分:9)

事实证明,我们将错误跟踪到使用Json.Net反序列化CancellationToken。

当代码仍在尝试使用已释放的OS句柄时,会出现潜在的问题。当然,当您的代码直接使用句柄时,就会发生这种情况。我们的代码没有这样做,但事实证明,这可能发生在Json.Net上。以下是:

我们有一个课程如下:

public class MyClass
{
   ...
}

// in one part of the code, this class was serialized & deserialized using Json.Net:
JsonConvert.SerializeObject(...);
JsonConvert.DeserializeObject<MyClass>(...);

当有人向MyClass添加了CancellationToken类型的属性时出现问题:

public class MyClass
{
    ...
    public CancellationToken Token { get; set; }
}

这是问题所在。序列化时,CancellationToken如下所示:

{"IsCancellationRequested":false,"CanBeCanceled":true,"WaitHandle":{"Handle":{"value":1508},"SafeWaitHandle":{"IsInvalid":false,"IsClosed":false}}}

请注意,这样做是懒惰的 - 创建令牌的WaitHandle属性,并序列化其底层操作系统句柄的值(1508)。

当我们反序列化令牌时,Json.Net将以new CancellationToken()开头(相当于CancellationToken.None)。然后,它将使用保存的Handle值继续填充该令牌WaitHandle的{​​{1}}属性。这会导致出错的一个显而易见的方法是默认的CancellationToken的WaitHandle现在指向一个可能无效的句柄。但是,更大的问题是更新句柄会取消引用WaitHandle的原始SafeHandle,从而允许垃圾收集器运行其终结器并进行清理。然后,您可以成为以下一系列事件的受害者:

  1. 句柄123被分配给池化数据库连接
  2. 反序列化将句柄123分配给默认取消令牌的WaitHandle
  3. 第二次反序列化将新句柄值分配给默认取消令牌的WaitHandle
  4. 垃圾收集器运行并最终确定已释放的123安全句柄值
  5. 数据库连接现在指向无效句柄
  6. 以下是使用IntPtr故意复制问题的一些代码:

    FileStream

答案 1 :(得分:3)

在搜索答案一段时间后没有成功,唯一最终解决错误的是iisreset

答案 2 :(得分:0)

您可以尝试进入SQL Server配置管理器并禁用一个或多个协议,看看是否有帮助。如果SQL Server和客户端位于同一台计算机上,则可能正在使用共享内存,并且系统已耗尽堆内存以处理句柄。尝试强制连接使用TCP,看看是否遇到同样的问题。

答案 3 :(得分:0)

IIS中的

将32位应用程序更改为false 通过应用程序池的高级设置

1 /在应用程序池中单击 2 /选择您的应用程序池,然后右键单击它 3 /选择高级座位... 4 /启用32位应用程序= false