1

I am running VS 2012 (Update 2) / .NET 4.5 / IIS Express 8.0 / Win 7 on my dev box. I am using async WebAPI (not web api 2) controllers.

Of late, I started noticing that when running the web api project with the VS debugger attached, I am getting intermittent "Thread was being aborted" errors. I had made some changes to Visual Studio recently and my knee jerk reaction was that was the cause of the issue.

I spent some time digging a bit deeper and I noticed that on inspecting the exception object, all the properties have the following error, "Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack." The error happens at different parts of the code when stepping through the code as is indicated in Rick Strahl's post:

This SO post suggests that it might be indicative of starting a backgound task using Task.Factory.StartNew

Is it correct/safe to use Task.Factory.StartNew in a web application ? Could it cause any issues (such as killing of the background task perhaps when running in a hosted process such as ASP.NET). Most of the operation are CRUD style operations and are not long running per se.

Also, this issue has not yet happened when running normally(without debugger attached) in IIS express / IIS 7.5.

Below is a code snippet that captures the essence of the nature of processing and the structure of the async controller.

Any insights would be much appreciated.

    public class SomeClass
{
    private Lazy<string> str;
    public SomeClass()
    {
        str = new Lazy<string>(Init);
    }

    private string Init()
    {
        try
        {
            string s =  "whatever";
            return s;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private string GetInternalString()
    {
        return str.Value;
    }

    public Task<string> GetString()
    {
        return Task.Factory.StartNew(() => GetInternalString());
    }
}


public class TestController : ApiController
{

    private async Task<string> GetStringAsync()
    {
        SomeClass c = new SomeClass();
        var x = await c.GetString();
        return x;
    }

    public async Task<string> Get(int id)
    {
        string s = await GetStringAsync();
        return s;
    }
}

UPDATE: I believe I figured out the problem(code sample updated). While debugging I added str.Value to the Watch widow AND set a breakpoint on string s = "whatever"; On Single stepping through the code I was able to repro the problem. Removing the str.Value from the watch window causes the issue to go away.

I think this is related to the explanation given in this SO post and the debugger is killing the thread to avoid a deadlock. I just need to validation that this is the case and not a true coding error related to the use of Task.Factory.StartNew

Community
  • 1
  • 1
Abhijeet Patel
  • 6,562
  • 8
  • 50
  • 93
  • If you down vote,have the decency to explain why. An OP invests quite sometime to frame and post questions here. If you can't get the help you seek,posting on SO in meaningless! – Abhijeet Patel Sep 26 '14 at 15:32
  • Please show the code with the real code instead of the delays, or at least the methods with their real method signatures with the body's commented out. I think in your efforts to "simplify" it you may be removing the code that is causing your problem entirely. – Scott Chamberlain Sep 26 '14 at 18:23

1 Answers1

1

Is it correct/safe to use Task.Factory.StartNew in a web application?

No. You should just do what you need to in the handler, without using another background thread.

The code you posted should not cause spurious thread aborts because it's blocking on the background thread (.Result). If your code starts background work via StartNew and does not wait for the results (await, .Result, or .Wait()), then that is dangerous and could cause spurious thread aborts. However, even though this code won't cause thread aborts, its use of StartNew is less efficient than just doing the work in the request context directly.

Just replace any StartNew(() => MyCode()).Result with MyCode().

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thanks Stephen.I used .Result for illustration purposes since I added an artificial Task.Delay to simulate processing.in reality it looks like Task.Factory.StartNew(()=> GetContactInternal(id)) – Abhijeet Patel Sep 26 '14 at 15:26
  • In that case, yes, it's dangerous. I have a [blog post on the subject](http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html). – Stephen Cleary Sep 26 '14 at 15:30
  • I read your post but in this case using backgroundworkitem is not appropriate. These are async controllers that return Task so the runtime is aware of the background processing. I still don't get why this would lead to a thread abort and that too only when debugging and examing variables in the watch window. – Abhijeet Patel Sep 26 '14 at 16:43
  • The runtime is only aware of it if you use `await`. If you just start them with `StartNew` and don't do anything with the returned task, then the runtime is not aware of it. – Stephen Cleary Sep 26 '14 at 17:55
  • That is precisely why I have awaits at all the required places. Do you see anything off? I also updated the code snippet indicating that .Delay and .Result are for illustrations only to simulate delay. – Abhijeet Patel Sep 26 '14 at 18:04
  • 1
    Please post a minimal code sample that reproduces the problem. – Stephen Cleary Sep 26 '14 at 18:22