【问题标题】:One or more errors occurred: PostAsJsonAsync发生一个或多个错误:PostAsJsonAsync
【发布时间】:2014-12-08 06:01:42
【问题描述】:

这是我得到的错误:

One or more errors occurred.
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at myProject.mymethod(Int32[] myIds) in path\MyClass.cs:line 758

这是那个方法:

private void mymethod(int[] myIds)
{
    var uri = new Uri(string.Format(UriPath, string.Format(MyPath)));
    var client = GetHttpClient(uri);

    var postModel = new PostModel
    {
        Ids = myIds,
        LastUpdate = NewItem ? null : _lastUpdated
    };

    if (client != null)
    {
        var response = client.PostAsJsonAsync(uri, postModel).Result;//this line crashes

        if (response.IsSuccessStatusCode)
        {
            //doSomething
        }
    }
}

我调用了很多这样的方法,除了这个之外,它们都可以工作。当它被击中时,它需要很长时间,然后抛出这个异常。使用所有其他方法都不会发生错误。

这是内部异常:

Inner.System.Threading.Tasks.TaskCanceledException: A task was canceled.

这是我的 GetCLient() 方法:

private HttpClient GetHttpClient(Uri uri)
{
    var handler = new HttpClientHandler
    {
        CookieContainer = CoockieContainer
    };

    return new HttpClient(handler)
    {
        BaseAddress = uri
    };
}

API 方法如下:

[HttpPost]
    public IList<MyModel> MyAPIMethod(PostModel model)
    {
        List<MyModel> myTranslations;
        using (var db = new myEntities(GetDbConnStrByUser(new GetCookies().GetUserName())))
        {
            myTranslations = db.tblTranslations.Where(it => model.Ids.Contains(it.id)
                                    && (!model.Update.HasValue || it.update > model.LastUpdate.Value))
                                    .Select(it => new MyModel
                                    {
                                        Id = it.id,
                                        Name = it.name,
                                        Description = it.desc,
                                        LanguageId = it.language_id                                            
                                    }).ToList();
        }

        return myTranslations.GroupBy(x => new { x.Id, x.LanguageId }).Select(x => x.First()).ToList();
    }

可能发生超时。

Fiddler 返回此错误:等待操作超时。

【问题讨论】:

  • 不要使用阻塞语句,而是使用异步。查看内部异常。
  • @JeroenVannevel 你所说的阻塞语句是什么意思?
  • .Result的调用是同步语句;你永远不会使用你可能拥有的异步性。更多关于正确使用 async-await 的信息:msdn.microsoft.com/en-us/library/hh191443.aspx
  • 发布整个异常。问题是你只显示“外部”异常,所以我们看不到发生了什么。查看异常的 InnerException 属性,看看到底出了什么问题。
  • 你解决过这个问题吗?遇到类似问题

标签: c# json


【解决方案1】:

.Result 试图将 Task 变成 T。它同步阻塞等待任务完成,只有在没有异常发生时才会返回 T。您应该预料到的两种异常类型是 OperationCanceledExceptions/TaskCanceledExceptions(当 HTTP 请求超时或使用 CancellationToken 并且令牌被取消时——我认为后者在这里不适用)和一般/HTTP 相关异常。

您可能遇到了 HTTP 超时情况。抛出异常需要很长时间吗?如果没有,您的 GetHttpClient 方法是什么样的?是否明确设置超时或取消令牌?

如果你想坚持同步方法而不返回任务,你应该这样做:

try
{    
    var response = client.PostAsJsonAsync(uri, postModel).Result;//this line crashes
} 
catch (OperationCanceledException oce) 
{
    // Tell the user that the request timed our or you cancelled a CancellationToken
}
catch (Exception exc) 
{
    // Look at the HttpClient docs and try to catch something more specific.  You don't want
    // to swallow StackOverflowExceptions or OutOfMemoryExceptions.
}

如果您愿意尝试异步,这正是您想要的:

private async Task mymethodAsync(int[] myIds)
{
    var uri = new Uri(string.Format(UriPath, string.Format(MyPath)));
    var client = GetHttpClient(uri);

    var postModel = new PostModel { ... };

    if (client != null)
    {
        try 
        {
            var response = await client.PostAsJsonAsync(uri, postModel);

            if (response.IsSuccessStatusCode)
            {
                //doSomething
            }
        }
        catch (OperationCanceledException oce) 
        {
            // because timeouts are still possible
        }
        catch (Exception exc) {
            // Because other things can still go wrong too (HTTP 500, parsing errors)
        }
    }
}

有关 .Result 调用如何使用 HttpClient 的更多信息,请参见此处:What happens while waiting on a Task's Result?

【讨论】:

  • 内部异常是TaskCanceledExceptions。您的第一个解决方案实际上并没有解决任何问题,它只是添加了 try-catch 块。
  • 是的,抛出异常需要很长时间。
  • Fiddler 返回此错误:等待操作超时。
  • Result 操作正在等待 Task 完成。 HttpClient 的默认超时时间为(我认为)30 秒。因此,.Result 最多等待 30 秒来等待以下 3 件事之一:结果、超时或异常。您只是在期待结果,但您正在遇到超时情况。假设您的请求有效,您的核心问题可能在远程服务器端(需要 > 30 秒才能生成响应)或与网络相关。阅读我帖子末尾的链接了解更多详情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-24
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 2021-11-27
  • 1970-01-01
相关资源
最近更新 更多