【问题标题】:WPF > WEBAPI > HttpClient > AWAIT = UI DelayWPF > WEBAPI > HttpClient > AWAIT = UI 延迟
【发布时间】:2012-12-17 19:09:21
【问题描述】:

我很困惑,我需要你的帮助。

我有一个 WPF 应用程序,它使用 ASYNC 和 AWAIT 调用 WEBAPI,我的 UI 出现延迟。

这是我正在使用的代码...

HttpResponseMessage response = await WEBAPI.GetHttpClient().GetAsync("api/COStateType/GetStateTypesByCountryID/" + Constants.COUNTRY_ID_USA);  
response.EnsureSuccessStatusCode(); 
App.stateTypes = await response.Content.ReadAsAsync<List<coStateType>>(); 

GetHttpClient 代码...

 public static HttpClient GetHttpClient()
    {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ABS2.WEBAPI.Uri"]);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        return client;
    }

这里是主要问题...

在启动过程中,我会显示一个带有移动齿轮(动画)的启动画面。实现对 WEBAPI 的调用后,动画不再流畅。我已经读到使用 HttpClient 的 ASYNC 调用会导致 UI 阻塞,这就是我的动画所发生的情况。

问题来了……

这个问题有什么办法吗?我尝试将此调用包装在 BackgroundWorker 和/或 Task 中,但均未解决问题。是否有另一种与不会导致此 UI 阻塞的 WEBAPI 通信的方式?我做错了什么?

非常感谢您的帮助!!!

【问题讨论】:

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


    【解决方案1】:

    @Stef7 和@Panagiotis - 你们说得对,UI 线程被阻塞了。我不确定我是否理解为什么异步调用会阻塞 UI 线程;我得做更多的研究。

    我已经尝试过后台线程,但直到我在任务上实施 ContinueWith 后才解决我的问题。

    感谢您的帮助。

    这是最终代码。

    public partial class Splash : Window
    {
        private TypeBO boType = new TypeBO();
        private Stopwatch swTotal = new Stopwatch();
        private Stopwatch swData= new Stopwatch();
    
        public Splash()
        {
            InitializeComponent();
            swTotal.Start();
        }
    
        private void GetData()
        {
            Assembly assembly = Assembly.GetExecutingAssembly();
            lblMessage.Content = "Please Wait...";
            lblVersion.Content = "Version: " + assembly.GetName().Version.Major + "." + assembly.GetName().Version.Minor + "." + assembly.GetName().Version.Revision;
    
            swData.Start();
    
            var backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += this.OnBackgroundWorkerDoWork;
            backgroundWorker.RunWorkerCompleted += OnBackgroundWorkerRunWorkerCompleted;
            backgroundWorker.RunWorkerAsync();
        }
    
        private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            WEBAPI.GetHttpClient().GetAsync("api/COStateType/GetStateTypesByCountryID/"
                + Constants.COUNTRY_ID_USA).ContinueWith(r =>
                {
                    r.Result.EnsureSuccessStatusCode();
                    e.Result = r.Result.Content.ReadAsAsync<List<coStateType>>().Result;
                }).Wait();
    
            swData.Stop();
            System.Diagnostics.Debug.Write("Splash - DATA - Total Elapsed Time - " + swData.Elapsed + Environment.NewLine);
        }
    
        private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            var backgroundWorker = sender as BackgroundWorker;
            backgroundWorker.DoWork -= this.OnBackgroundWorkerDoWork;
            backgroundWorker.RunWorkerCompleted -= OnBackgroundWorkerRunWorkerCompleted;
    
            App.stateTypes = e.Result as List<coStateType>;
    
            coStateType pleaseSelectStateType = new coStateType() { State_ID = 0, State_Nm = "Select One", Country_ID = 1 };
            App.stateTypes.Insert(0, pleaseSelectStateType);
    
            sbHideState.Completed += (snd, eva) =>
            {
                //Pre-Load User Controls
                Assembly assembly = this.GetType().Assembly;
                UserControl ucBHSearch = (UserControl)assembly.CreateInstance(string.Format("{0}.BHSearch", "ABS2.WPF.ADMIN.UserControls.BusinessHierarchy"));
                UserControl ucBHDetails = (UserControl)assembly.CreateInstance(string.Format("{0}.BHDetails", "ABS2.WPF.ADMIN.UserControls.BusinessHierarchy"));
                App.userControls.Add("BHD", ucBHDetails);
                App.userControls.Add("BHS", ucBHSearch);
    
                Login winLogin = new Login();
                winLogin.Show();
    
                swTotal.Stop();
                System.Diagnostics.Debug.Write("Splash - UI - Total Elapsed Time - " + swTotal.Elapsed + Environment.NewLine + Environment.NewLine);
                swTotal.Reset();
                this.Close();
            };
            sbHideState.Begin(gridSplash);
        }
    
        private void Window_Loaded_1(object sender, RoutedEventArgs e)
        {
            lblMessage.Content = "";
            lblVersion.Content = "";
            sbDefaultState.Begin(gridSplash);
            sbRotateState.Begin(gridSplash);           
        }
    
        private void window_ContentRendered(object sender, EventArgs e)
        {
            sbShowState.Completed += (snd, eva) =>
            {
                GetData();
            };
            sbShowState.Begin(gridSplash);
        }
    }
    

    【讨论】:

      【解决方案2】:

      您需要使用“任务”函数来调用异步。这不会阻塞您的 GUI 主线程,您也不需要使用后台工作程序或线程。 “Task”、“Async”、“Await”并存。

      【讨论】:

        【解决方案3】:

        await 完成等待时,在原始上下文(线程)中继续执行,在您的情况下是 UI 线程。

        这允许您的代码在不使用调度程序的情况下访问 UI 控件。这意味着在最后一个 await 之后的任何昂贵代码实际上都会在 UI 线程上运行。

        如果您希望您的代码继续在单独的线程上运行,则应在调用 await 之后添加 .ConfigureAwait(false),即。

        await response.Content.ReadAsAsync<List<coStateType>>().ConfigureAwait(false);
        

        在这种情况下,您应该注意使用 Dispatcher 或 SynchronizationContext 方法访问 UI 控件Post/Send,例如。

        SynchronizationContext.Current.Post(_=>progressBar.Value+=5,null);
        

        【讨论】:

          【解决方案4】:

          您发布的所有代码都在 UI 线程中执行。异步功能可帮助您在 UI 线程无事可做时(在 Web 请求期间)不阻塞,但如果您让 UI 线程忙于太多代码,您的动画总会出现问题。

          我会尝试将所有与 Web 相关的代码移动到后台工作程序中,并仅将简短的 UI 更新发布到 UI 线程。既然你写道你已经尝试过后台工作人员,我不得不假设 UI 更新需要太长时间。

          如果您有性能分析器,请分析 UI 线程的繁忙时间以获得更好的画面。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-02-22
            • 2018-01-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-10-17
            相关资源
            最近更新 更多