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

2
  • 1
    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! Commented Sep 26, 2014 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. Commented Sep 26, 2014 at 18:23

1 Answer 1

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().

Sign up to request clarification or add additional context in comments.

6 Comments

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))
In that case, yes, it's dangerous. I have a blog post on the subject.
I read your post but in this case using backgroundworkitem is not appropriate. These are async controllers that return Task<T> 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.
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.
Please post a minimal code sample that reproduces the problem.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.