CancellationToken: ObjectDisposedException when reusing JsonHttpClient

following the reply here and according to the fact that JsonHttpClient should be thread safe we’ve refactored our web service proxy to use single, shared instance of JsonHttpClient.

Unfortunately we started to get some ObjectDisposedExceptions saying The CancellationTokenSource has been disposed.

further investigation resulted in:

  1. single CancellationTokenSource is used for the lifetime of the JsonHttpClient
  2. it is being disposed when an exception is returned from http call
  3. SendAsync creates new instance of CancellationTokenSource it it is null, however …

… what we believe is happening is a rare case of race condition.

  1. request #1 is being fired, it uses the current instance of CTS
  2. request #2 is being initialized in parallel, using the current instance of CTS
  3. request #1 fails, current instance of CTS is being disposed
  4. request #2 initialization proceeds to the point where (.NET’s) HttpClient calls CreateLinkedTokenSource on the (already disposed) CTS

here’s the stack trace

System.ObjectDisposedException: The CancellationTokenSource has been disposed.
   at System.Threading.CancellationTokenSource.ThrowObjectDisposedException()
   at System.Threading.CancellationTokenSource.InternalRegister(Action`1 callback, Object stateForCallback, SynchronizationContext targetSyncContext, ExecutionContext executionContext)
   at System.Threading.CancellationToken.Register(Action`1 callback, Object state, Boolean useSynchronizationContext, Boolean useExecutionContext)
   at System.Threading.CancellationToken.InternalRegisterWithoutEC(Action`1 callback, Object state)
   at System.Threading.CancellationTokenSource.CreateLinkedTokenSource(CancellationToken token1, CancellationToken token2)
   at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at ServiceStack.JsonHttpClient.SendAsync[TResponse](String httpMethod, String absoluteUrl, Object request, CancellationToken token)
   at ServiceStack.JsonHttpClient.PutAsync(IReturnVoid requestDto)

Please note the problem is very rare, it happens 2-3 times a day under a moderate/heavy traffic

I’ve removed support for CancelAsync and added overloads containing a CancellationToken for each async API in this commit. These new API’s are outside the IServiceClient interfaces contract so they’d need to be called on the JsonHttpClient concrete type if needed.

This change is available from v5.1.1 that’s now available on MyGet.

Perfect, thank you for the quick response and fix.

Any estimations when will it become available as part of stable (NuGet) package?

the problem concerns a rather large project, and it takes a lot of planning and decision-making process is quite long when it comes to upgrading packages. We’re not even on SS 5 yet, but planning to upgrade soon. I’d like this to be a part of upgrade but we need it to be stable first.

Pre release packages on MyGet are the same as the official Nuget packages, they’re just published to MyGet instead of NuGet.

There’s no ETA on future releases except need to wait before next release of VS.NET which contains an updated version of Xamarin which adds supports for Span which ServiceStack.Text was rewritten to use.

1 Like