\\ Home Page : Articolo : Stampa
System.InvalidOperationException tra thread
Di Marco Tenuti (del 21/12/2012 @ 15:32:14, in .NET Framework, linkato 2774 volte)

Sono incappato in questa eccezione con .NET Framework 4.0 e Winforms, usando un meccanismo di callback asincrona e thread pooling per la gestione del timeout:

System.InvalidOperationException was unhandled
Message=L'operazione di annullamento ha rilevato un contesto differente da quello applicato nell'operazione Set corrispondente. Probabilmente un contesto è stato Set nel thread e non è stato ripristinato (annullato).

   in System.Threading.SynchronizationContextSwitcher.Undo()
   in System.Threading.ExecutionContextSwitcher.Undo()
   in System.Threading.ExecutionContext.runFinallyCode(Object userData, 
			Boolean exceptionThrown)
   in System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper
			(Object backoutCode, Object userData, Boolean exceptionThrown)
   in System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup
			(TryCode code, CleanupCode backoutCode, Object userData)
   in System.Threading.ExecutionContext.RunInternal(ExecutionContext 
			executionContext, ContextCallback callback, Object state)
   in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, 
			ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, 
			ContextCallback callback, Object state)
   in System.Net.ContextAwareResult.Complete(IntPtr userToken)
   in System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
   in System.Net.HttpWebRequest.SetResponse(Exception E)
   in System.Net.HttpWebRequest.SetAndOrProcessResponse(Object responseOrException)
   in System.Net.ConnectionReturnResult.SetResponses(ConnectionReturnResult returnResult)
   in System.Net.Connection.CompleteConnectionWrapper(Object request, Object state)
   in System.Net.PooledStream.ConnectionCallback(Object owningObject, 
			Exception e, Socket socket, IPAddress address)
   in System.Net.ServicePoint.ConnectSocketCallback(System.IAsyncResult)
   in System.Net.LazyAsyncResult.Complete(IntPtr)
   in System.Net.ContextAwareResult.Complete(IntPtr)
   in System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr)
   in System.Net.Sockets.Socket.ConnectCallback()
   in System.Net.Sockets.Socket.RegisteredWaitCallback(System.Object, Boolean)
   in System.Threading._ThreadPoolWaitOrTimerCallback.
			PerformWaitOrTimerCallback(System.Object, Boolean)

Pare che in Microsoft non ne siano venuti a capo, ma al momento la soluzione pare essere la seguente:

  1. non invocare Application.DoEvents al di fuori del main thread del processo
  2. usare il l'invocazione tramite Invoke/BeginInvoke nel caso in cui l'evento scatenante risponda vero all'interrogazione myControl.InvokeRequired

In realtà il tamponamento maggiore al problema pare essere dato dall'instanziazione della callback assicurandosi di resettare il contesto di sincronizzazione:

  Dim oldSyncContext As System.Threading.SynchronizationContext

  oldSyncContext = System.Threading.SynchronizationContext.Current
    System.Threading.SynchronizationContext.SetSynchronizationContext(Nothing)
    myAsyncResult = myRequest.BeginGetResponse(AddressOf ReadResponseAsync, myRequest)
    If (Not _doSynchronous) Then
      System.Threading.ThreadPool.RegisterWaitForSingleObject(myAsyncResult.AsyncWaitHandle,
        New System.Threading.WaitOrTimerCallback(AddressOf TimeoutAsync),
         myRequest, timeoutMs, True)
    End If
    System.Threading.SynchronizationContext.SetSynchronizationContext(oldSyncContext)

Su stackoverflow.com ho trovato questo ottimo articolo e discussione.