【问题标题】:Calling async Web API method from App.OnStartup从 App.OnStartup 调用异步 Web API 方法
【发布时间】:2015-05-12 03:28:04
【问题描述】:

我将 App.OnStartup 更改为异步,以便我可以在 Web api 上调用异步方法,但现在我的应用程序不显示它的窗口。我在这里做错了什么:

    protected override async void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        HttpResponseMessage response = await TestWebAPI();
        if (!response.IsSuccessStatusCode)
        {
            MessageBox.Show("The service is currently unavailable"); 
            Shutdown(1);
        }

        this.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
    }

    private async Task<HttpResponseMessage> TestWebAPI()
    {
        using (var webClient = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
        {
            webClient.BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiAddress"]);
            HttpResponseMessage response = await webClient.GetAsync("api/hello", HttpCompletionOption.ResponseContentRead).ConfigureAwait(false);
            return response;
        }
    }
}

如果我对 TestWebAPI 进行异步调用,它会显示正常。

【问题讨论】:

  • 您的编码方式意味着您的消息框和/或 MainWindow.xaml 在异步方法完成之前不会出现。 await 关键字使所有后续代码行成为任务完成时将执行的延续。如果您详细说明自己尝试做什么,那么有人可以更好地帮助您。
  • 如果我不需要,只是试图不显示我的主窗口。因此,如果 Web 服务关闭,请通知用户并关闭。在这种情况下,Web 服务处于活动状态,但我看不到主窗口。
  • 我可以通过在 GetAsync 方法上调用 .Result 来使其全部同步,但是我会因此失去任何好处吗?
  • 您的代码是按顺序和异步执行的(即 TestWebAPI 是异步的,但 response.IsSuccessStatusCode 的测试以及它之后的所有内容都是从 TestWebAPI 顺序执行的)。您希望您的异步方法在“在后台”执行与它后面的代码相关的——这意味着不使用await。我建议将“异步”添加到方法中,这样更清楚的是调用该方法会异步执行某些操作。

标签: c# wpf asp.net-web-api async-await


【解决方案1】:

我怀疑 WPF 期望在OnStartup 返回之前设置StartupUri所以,我会尝试在Startup 事件中显式创建窗口:

private async void Application_Startup(object sender, StartupEventArgs e)
{
  HttpResponseMessage response = await TestWebAPIAsync();
  if (!response.IsSuccessStatusCode)
  {
    MessageBox.Show("The service is currently unavailable"); 
    Shutdown(1);
  }
  MainWindow main = new MainWindow();
  main.DataContext = ...
  main.Show();
}

【讨论】:

  • 这解决了它就好了。一个相关的问题:异步给我带来了什么?在我检查我的网络服务时,我似乎不需要 UI 线程做任何事情,因为如果服务不可用,我想在不显示 UI 的情况下关闭...
  • 在这种情况下它不会为您带来任何好处。例如,如果您要显示一个可以移动/最小化的初始屏幕(这不是一个坏主意),那么它将允许该初始屏幕具有响应性。
【解决方案2】:

你试过了吗?

this.OnStartup += async (s, e) =>
   {
     ...
   };

或者

this.Loaded += async (s, e) =>
   {
     ...
   };

或者您可以选择另一个相关的事件。

【讨论】:

  • 不要按照那样做。但看起来我的代码很好,只是 WPF 句柄以它自己的方式显示主窗口,所以斯蒂芬建议的改变奏效了。
猜你喜欢
  • 2020-03-10
  • 1970-01-01
  • 2015-06-04
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-19
  • 1970-01-01
相关资源
最近更新 更多