繁体   English   中英

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

[英]C# Async / Await never responding in MVC4

我一直在努力与异步/等待一周。 一些背景知识:下面的代码是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()和GetParentCategoriesAsync()中放置断点。 一切都会一直触发,直到等待wc.DownloadStringTaskAsync(targeturi)命令。 那是停止的地方。

我已将ConfigureAwait(continueOnCapturedContext:false)添加到所有任务中,但这没有帮助。 我假设问题是线程不在同一个上下文中。 但是,我不确定。 但我确信,我做错了什么。 我只是不确定是什么。 它或者我只是想尝试做一些用.NET 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建议的那样一直保持异步。 在那之后,我对任何我想要的异步模式没有任何问题。

暂无
暂无

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

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