ThreadAbortException when calling Task.Result

I have the following code where I am trying to query a remote endpoint using HttpClient :

 using (var client = new HttpClient()) { client.BaseAddress = _serviceBaseAddress; Task<HttpResponseMessage> readResponseTask = client.GetAsync(relativeUri); readResponseTask.Wait(); using (var response = readResponseTask.Result) { if (response.StatusCode == HttpStatusCode.NotFound || !response.IsSuccessStatusCode) { return default(TResult); } Task<TResult> readContentTask = response.Content.ReadAsAsync<TResult>(); readContentTask.Wait(); TResult value = readContentTask.Result; return value; } } 

.. and sometimes I would get a ThreadAbortException in readResponseTask.Result like this:

System.Threading.ThreadAbortException: thread terminated. in System.Threading.Monitor.ObjWait (Boolean exitContext, Int32 millisecondsTimeout, Object obj) in System.Threading.ManualResetEventSlim.Wait (Int32 millisecondsTimeout, CancellationToken cancelationTokenTokenTokenWtokenTokenTokenTokenTokenTokenTokenTokenTokenTokenToken in System.Threading.Tasks.Task.InternalWait (Int32 millisecondsTimeout, CancellationToken cancelationToken) in System.Threading.Tasks.Task.Wait (Int32 millisecondsTimeout, CancellationToken cancelationToken)

Under what circumstances .Result throws such an exception? I tried to simulate a timeout on a remote endpoint, but I got an exception in .Wait() instead of .Result . Since the exception occurs after .Wait() , I assume that the result has already been returned from the remote site, but for some reason something went wrong when it tries to access the result.

Any clues? Could this be something related to concurrency flow?

+7
multithreading c # thread-safety asp.net-web-api
source share
4 answers

I would get a ThreadAbortException in readResponseTask.Result

No no. The call stack clearly shows that this is actually a Wait () call that threw an exception. Note the frequent occurrence of the word "wait" in the trace.

It's hard to understand how confused you are. Keep in mind that the get.Result getter property is very small , and it will be enabled when you run the Release build of your program. So you can never see it in the stack trace.

You might be ahead just by deleting the Wait () call. This is optional, the getult Result property already waits if necessary.

+6
source share

During Wait (), the thread is interrupted externally. No one can say exactly why.

Enabling network client tracing can help identify the root cause.

+3
source share

First, do not use .*Async() if you intend to call .Wait() immediately. This is bad practice and will most likely lead to erroneous results. Instead, use synchronous versions of calls, client.Get(relativeUri) and the following:

 TResult value = response.Content.ReadAs<TResult>(); return value; 

If you intend not to use the asynchronous programming model .NET frameworks.

But if you prefer to use the capabilities of asynchronous I / O, you should do this in accordance with best practices. Use async / await keywords and make your methods look like synchronization using the capabilities of asynchronous .NET keywords.

I can only imagine that the entry point to your method looks something like this:

 public TResult InvokeClientGet<TResult>(string relativeUri) { // ... left out for brevity } 

This actually prevents you from using the async / wait keywords. Instead, try the following:

  public async Task<TResult> InvokeClientGet<TResult>(string relativeUri) { try { using (var client = new HttpClient { BaseAddress = _serviceBaseAddress }) { using (var response = await client.GetAsync(relativeUri)) { if (response.StatusCode == HttpStatusCode.NotFound || !response.IsSuccessStatusCode) { return default(TResult); } return await response.Content.ReadAsAsync<TResult>(); } } catch (Exception ex) { // Handle exceptional conditions } } 

A few words about System.Threading.ThreadAbortException .

When you call the Abort method to kill a thread, the common runtime throws a ThreadAbortException. ThreadAbortException is a special exception that can be caught, but it will be automatically raised again at the end of the catch block. When this exception occurs, the runtime executes all finally blocks until the thread ends. Because a thread can perform unlimited computation in finally blocks or call Thread.ResetAbort to cancel an interrupt, there is no guarantee that the thread will ever end. If you want to wait for the interrupted thread to finish, you can call the Thread.Join method. Join is a blocking call that does not return until the thread actually terminates.

With that said, if something calls .Abort() and raises this exception. There is not much to prevent this. Regardless, try to follow best practices.

+2
source share

I had the same problem when testing a method through Unit-Tests that sent Data to a WebService. (ik there are better ways to do this)

The problem was that Unit-Test called my asynchronization method, but did not wait for the WebService call to complete. This canceled the WebService call, and I got a ThreadAbortException .

 [TestMethod] public void WebServiceTest01(){ BusinessLogic bs = new BusinessLogic(); bs.CallWebService(); } 

All I had to do was do a Unit-Test until the WebService call completed by adding the await keyword.

 [TestMethod] public void WebServiceTest01(){ BusinessLogic bs = new BusinessLogic(); var result = await bs.CallWebService(); Assert.NotNull(result); } 
0
source share

All Articles