c# Async / Await在MVC4中永远不会响应

本文关键字:永远 响应 MVC4 Async Await | 更新日期: 2023-09-27 18:17:37

我已经和async/await纠结了一个星期了。一些背景:下面的代码是一个MVC4网站项目的一部分。这个网站有大量的API调用。我们的目标是让这些API调用并行发生,而不是同步发生,以提高站点的响应能力。现在所有的API调用都互相阻塞。所以如果一页需要4次调用…更长的加载时间

我已经为所有API调用的同步和异步版本构建了单独的方法。我遇到的问题是await永远不会响应。我想这和这个问题有关。然而,我真的不知道如何解决它。我试过ConfigureAwait(false),但没有帮助我。

代码如下:

控制器中的初始调用看起来是这样的:

BaseData bdata = API.GetBaseData().Result;

我想在这里使用await,但这不是一个没有AsyncController的选项,由于需要请求/响应访问,我们不能使用。其他方法在API类中:

internal static async Task<BaseData> GetBaseData() {
    var catTask = GetParentCategoriesAsync();
    var yearTask = GetYearsAsync();
    await Task.WhenAll(new Task[] { catTask, yearTask });
    var bdata = new BaseData {
        years = await yearTask,
        cats = await catTask
    };
    return bdata;
}
internal static async Task<List<APICategory>> GetParentCategoriesAsync() {
    try {
        WebClient wc = new WebClient();
        wc.Proxy = null;
        string url = getAPIPath();
        url += "GetFullParentCategories";
        url += "?dataType=JSON";
        Uri targeturi = new Uri(url);
        List<APICategory> cats = new List<APICategory>();
        var cat_json = await wc.DownloadStringTaskAsync(targeturi);
        cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json);
        return cats;
    } catch (Exception) {
        return new List<APICategory>();
    }
}
internal static async Task<List<double>> GetYearsAsync() {
    WebClient wc = new WebClient();
    wc.Proxy = null;
    Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON");
    var year_json = await wc.DownloadStringTaskAsync(targeturi);
    List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json);
    return years;
}

当调用这些方法时,我可以在GetYearsAsync()和getparentcategoresasync()中设置断点。直到await wc.DownloadStringTaskAsync(targeturi)命令执行为止。到此为止。

我已经添加了ConfigureAwait(continueOnCapturedContext: false)到所有的任务,但这没有帮助。我假设问题是线程不在同一上下文中。然而,我不确定。然而,我确信我做错了什么。我只是不确定是什么。要么就是这样,要么就是我只是想做一些不能用。net MVC4完成的事情。如有任何意见,我将不胜感激。

c# Async / Await在MVC4中永远不会响应

这个问题实际上是由于WebClient,它将总是同步回请求上下文(由于Result调用而被阻塞)。

您可以使用HttpClient代替ConfigureAwait(false):

internal static async Task<BaseData> GetBaseDataAsync() {
  var catTask = GetParentCategoriesAsync();
  var yearTask = GetYearsAsync();
  await Task.WhenAll(catTask, yearTask).ConfigureAwait(false);
  var bdata = new BaseData {
    years = await yearTask,
    cats = await catTask
  };
  return bdata;
}
internal static async Task<List<APICategory>> GetParentCategoriesAsync() {
  try {
    var client = new HttpClient();
    string url = getAPIPath();
    url += "GetFullParentCategories";
    url += "?dataType=JSON";
    Uri targeturi = new Uri(url);
    List<APICategory> cats = new List<APICategory>();
    var cat_json = await client.GetStringAsync(targeturi).ConfigureAwait(false);
    cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json);
    return cats;
  } catch (Exception) {
    return new List<APICategory>();
  }
}
internal static async Task<List<double>> GetYearsAsync() {
  var client = new HttpClient();
  Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON");
  var year_json = await client.GetStringAsync(targeturi).ConfigureAwait(false);
  List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json);
  return years;
}

你可以这样调用它:

BaseData bdata = API.GetBaseDataAsync().Result;

但是,我强烈建议您这样称呼它:

BaseData bdata = await API.GetBaseDataAsync();

您会发现await之前和之后的代码都可以很好地访问请求和响应上下文。

我最终采纳了Servy和Stephen Cleary的建议。根据Stephen的响应,我意识到我可以访问请求/响应,只要我在控制器中进行任何异步调用之前这样做。

如果我将HttpContext存储在变量中,我可以将该上下文传递给任何需要访问它的模型/服务方法。这让我可以像Servy建议的那样进行异步操作。在那之后,我没有任何问题,我想与异步模式。