简体   繁体   English

从静态函数调用InsertAsync会引发ThreadAbortException

[英]Calling InsertAsync from static function throws ThreadAbortException

I expect there's probably a simple fix for this but I just can't see it. 我希望可能有一个简单的解决方法,但是我看不到。

I'm trying to insert data into an Azure Mobile Services DB from a C# Console program. 我正在尝试从C#控制台程序将数据插入到Azure移动服务数据库中。 However when the program is run from within VS (via F5), the data is not being inserted nor is an exception being thrown (that I can see) during the regular course of running the program. 但是,当从VS(通过F5)内部运行程序时,在正常运行程序期间不会插入数据,也不会抛出异常(我可以看到)。 When I set a breakpoint to the await dataModel.InsertAsync(data) line and run that in the Immediate Window it throws a ThreadAbortException. 当我在await dataModel.InsertAsync(data)行中设置断点并在“即时窗口”中运行该断点时,它将引发ThreadAbortException。 Any help is appreciated. 任何帮助表示赞赏。

Namespace TestApp {
class Program
{
    public static MobileServiceClient MobileService = new MobileServiceClient(
    "https://x.azure-mobile.net/",
    "API key");

    public static IMobileServiceTable<performance> dataModel = Program.MobileService.GetTable<performance>();

    static void Main(string[] args)
    {
        try
        {
            var test = new performance("http://www.example.com");
            var x = InsertItem(test);
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.StackTrace);
        }
    }
static public async Task InsertItem(performance data)
{
        await dataModel.InsertAsync(data).ConfigureAwait(false);
}
}

class performance
{
    [JsonProperty(PropertyName = "id")]
    string Id { get; set; }
    [JsonProperty(PropertyName = "uri")]
    string Uri { get; set; }

    public performance(string uri)
    {
        Uri = uri;
    }

}
}

Your problem comes from the fact that var x = InsertItem(test); 您的问题来自以下事实: var x = InsertItem(test); is a non blocking call. 是非阻塞呼叫。 When you get to await dataModel.InsertAsync(data).ConfigureAwait(false); 当您await dataModel.InsertAsync(data).ConfigureAwait(false); the function InsertItem immediately returns with a Task . 函数InsertItem立即返回Task

Normally the correct approach would be do await InsertItem(test); 通常正确的方法是await InsertItem(test); however because your code is being called from Main you can't make the function async . 但是,由于您的代码是从Main调用的,因此无法使函数async So for this console application (it would not be the correct choice if running in WinForms or WPF app) You need to put a x.Wait() before the end of your try-catch block. 因此,对于此控制台应用程序 (如果在WinForms或WPF应用程序中运行,这将不是正确的选择),您需要在try-catch块末尾放置x.Wait()

static void Main(string[] args)
{
    try
    {
        var test = new performance("http://www.example.com");
        var x = InsertItem(test);

        //This makes the program wait for the returned Task to complete before continuing.
        x.Wait();
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.StackTrace);
    }
}

However if you where to do this in a WPF or WinForms app you would just make the calling function (Assuming the function was a event) async. 但是,如果您要在WPF或WinForms应用程序中执行此操作,则只需使调用函数(假定该函数是一个事件)就可以异步进行。

private async void Button1_OnClick(object sender, EventArgs e)
{
    try
    {
        var test = new performance("http://www.example.com");

        //The code now waits here for the function to finish.
        await InsertItem(test);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.StackTrace);
    }
}

Do not do async void function calls unless you are in a event delegate function 除非您处于事件委托函数中,否则请勿执行async void函数调用

I created a small test to (somewhat) simulate what you're doing. 我创建了一个小测试来(某种程度上)模拟您在做什么。 When the awaited task in InsertItem takes very little or no time at all, the task returned by the var x = InsertItem(test) line returns a task in the RanToCompletion state and the debugger acts as expected. 当在InsertItem中等待的任务花费很少或根本没有时间时,由var x = InsertItem(test)行返回的任务将返回RanToCompletion状态的任务,并且调试器将按预期方式工作。

However, when I make the awaited task do something substantial, such as Thread.Sleep(5000), then I get the behavior you're describing and the task returned by the var x = InsertItem(test) line returns a task in the WaitingForActivation state. 但是,当我使等待的任务执行实质性的操作(例如Thread.Sleep(5000))时,我得到了您正在描述的行为,并且var x = InsertItem(test)行返回的任务在WaitingForActivation中返回了一个任务州。

When I put Task.WaitAll(x) following the var x = InsertItem(test) line, then I get the behavior that I think we both expect and x.Status is RanToCompletion. 当我将Task.WaitAll(x)放在var x = InsertItem(test)行之后时,我得到了我认为我们都期望的行为,而x.Status是RanToCompletion。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM