从静态函数调用InsertAsync会抛出ThreadAbortException

本文关键字:ThreadAbortException InsertAsync 静态 函数调用 | 更新日期: 2023-09-27 18:08:15

我希望可能有一个简单的修复,但我只是看不到它。

我试图从c#控制台程序插入数据到Azure移动服务数据库。然而,当程序从VS(通过F5)内运行时,数据没有被插入,也没有在运行程序的常规过程中抛出异常(我可以看到)。当我设置一个断点到await dataModel.InsertAsync(data)行并在即时窗口中运行时,它会抛出一个ThreadAbortException。如有任何帮助,不胜感激。

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

从静态函数调用InsertAsync会抛出ThreadAbortException

您的问题来自var x = InsertItem(test);是非阻塞调用的事实。当你到达await dataModel.InsertAsync(data).ConfigureAwait(false);时,函数InsertItem立即返回Task

通常正确的方法是做await InsertItem(test);,但是因为你的代码是从Main调用的,你不能让函数async。因此,对于这个控制台应用程序(如果在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);
    }
}

然而,如果你想在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);
    }
}

不要调用async void函数,除非你是在一个事件委托函数

我创建了一个小测试来(某种程度上)模拟您正在做的事情。当InsertItem中等待的任务花费很少时间或根本不花费时间时,由var x = InsertItem(test)行返回的任务将返回一个处于RanToCompletion状态的任务,并且调试器将按照预期进行操作。

但是,当我让等待的任务做一些实质性的事情时,例如Thread.Sleep(5000),然后我得到您所描述的行为,var x = InsertItem(test)行返回的任务返回一个处于WaitingForActivation状态的任务。

当我把Task.WaitAll(x)后面的var x = InsertItem(test)行,然后我得到的行为,我认为我们都期望和x.状态是RanToCompletion