异步web api控制器中的“线程被中止”错误

时间:2014-09-26 06:12:29

标签: c# asp.net visual-studio-2012 asp.net-web-api

我在我的开发箱上运行VS 2012(Update 2)/ .NET 4.5 / IIS Express 8.0 / Win 7。 我正在使用异步WebAPI(而不是web api 2)控制器。

最近,我开始注意到在运行带有VS调试器的web api项目时,我正在断断续续的" Thread正在被中止" 错误。 我做了一些changes to Visual Studio recently并且我的膝盖反射是这个问题的原因。

我花了一些时间深入挖掘,我注意到在检查异常对象时,所有属性都有以下错误, "无法评估表达式,因为代码已优化或本机框架位于调用堆栈之上。" Rick Strahl's post

中所示,当单步执行代码时,错误会发生在代码的不同部分

SO post 表明它可能表示使用Task.Factory.StartNew

启动背景任务

在Web应用程序中使用Task.Factory.StartNew是否正确/安全? 它是否会导致任何问题(例如,在托管进程(如ASP.NET)中运行时可能会终止后台任务)。 大多数操作都是CRUD样式的操作,并且本身运行时间不长。

此外,在IIS Express / IIS 7.5中正常运行(未连接调试器)时,尚未发生此问题。

下面是一段代码片段,它捕捉了处理性质和异步控制器结构的本质。

非常感谢任何见解。

    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;
    }
}

更新     我相信我发现了问题(代码示例已更新)。调试时我将str.Value添加到Watch寡妇并在string s = "whatever";上设置断点。单步执行代码我能够重现问题。 从观察窗口中删除str.Value会导致问题消失。

我认为这与in this SO post给出的解释有关 并且调试器正在杀死线程以避免死锁。我只需要验证是否是这种情况,而不是与使用Task.Factory.StartNew

相关的真正编码错误

1 个答案:

答案 0 :(得分:1)

  

在Web应用程序中使用Task.Factory.StartNew是否正确/安全?

没有。您应该在处理程序中执行您需要的操作,而不使用其他后台线程。

您发布的代码不应导致虚假线程中止,因为它在后台线程(.Result)上阻塞。如果您的代码通过StartNew开始后台工作并且等待结果(await.Result.Wait()),那么危险并可能导致虚假线程中止。但是,即使此代码不会导致线程中止,它使用StartNew的效率也不如直接在请求上下文中完成。

只需将StartNew(() => MyCode()).Result替换为MyCode()