【问题标题】:HttpClient not executing GetAsync in Minimized UWP AppHttpClient 未在最小化 UWP 应用程序中执行 GetAsync
【发布时间】:2018-08-10 11:39:18
【问题描述】:

我正在做一个播放几个视频的项目。为了能够播放这些视频,我需要在应用程序通过HttpClientSystem.Net.Http 请求时获取他们的数据。一切正常,当应用处于前台时,UWP 应用会从 Internet 下载所需的信息。

一旦应用离开前台并被用户最小化,HttpClient,无论是来自 System.Net.Http 命名空间还是 Windows.Web.Http 命名空间,都不起作用。我什至尝试在那里设置一个断点,只要我继续前进,HttpClient 不会响应await client.GetAsync() 方法并停留在那里而不返回任何结果,除非您再次激活应用程序然后它返回任何值。我不能使用BackgroundTasks,因为他们需要Triggers,但我需要按需访问数据。

我还阅读了this 的文章描述请求ExtendedExecutionState,但结果仍然相同。当应用收到播放项目列表的请求时,我会请求此状态。即使得到Allowed 的结果,HttpClient 的行为也与上述相同。

是否有任何方法可以在请求时执行与互联网相关的查询并获取一些信息?

我执行的从互联网访问数据的代码是:

public static async Task<string> GetResponseDataFromAPI(string apiRequestUrl, CancellationTokenSource cts = default)
{
    cts = cts ?? new CancellationTokenSource(TimeSpan.FromSeconds(20));
    try
    {
        var responseData = await AuthRequestHelper.globalHttpClient.GetAsync(apiRequestUrl, cts.Token);
        var result = await responseData.Content.ReadAsStringAsync();
        return result;
    }
    catch (Exception ex)
    {
        INotifyHelper.iNotifyObject.IsVideoLoading = false;
        INotifyHelper.iNotifyObject.IsDataLoading = false;
        // show error
        return "{ \"error\": {\"code\": " + $"\"{ex.HResult}\", \"message\": \"{ex.Message}\"" + "} }";
    }
}

然后分析返回的值以从中获取所需的数据。

请求ExtendedExecutionSession执行的代码是:

public static async void RequestBackgroundExtendedExecution()
{
    using (var session = new ExtendedExecutionSession())
    {
        session.Reason = ExtendedExecutionReason.Unspecified;
        session.Description = "Background Playlist Playback";
        session.Revoked += Session_Revoked;
        if (await session.RequestExtensionAsync() is ExtendedExecutionResult result)
        {
            if (result == ExtendedExecutionResult.Denied)
            {
                // show user that background playlist playback will not be possible
            }
        }
    }
}

在最小化状态下是否可以执行任何请求的操作?非常感谢您指出正确方向的一点帮助。谢谢

【问题讨论】:

标签: c# uwp


【解决方案1】:

BackgroundTransfer classes 专门设计用于在后台下载数据,即使应用程序暂停或关闭。

HttpClient 更适合快速完成的非常短的下载。对于视频等长时间下载,请使用Windows.Networking.BackgroundTransfer.BackgroundDownloader。如果您需要在下载完成时处理文件,您可以使用该完成作为后台任务的触发器。

有关概述和操作方法,请参阅提供的文档链接。在https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/BackgroundTransfer 有一个完整的样本

【讨论】:

  • 我想你还没有完全理解我的问题,我使用HttpClient 来获取视频的ID 或URL。我不使用HttpClient 下载整个视频。 BackgroundTransfer 是否仍然适用于此类短取操作?
  • 事实上,如果应用程序被最小化,await 函数将不会运行。它等待应用程序进入前台然后继续,否则它会暂停。所以我决定使用 Task.Result 方法,因为用户没有使用应用程序,我可以在不阻塞应用程序 UI 的情况下获得异步方法的结果。
【解决方案2】:

所以我决定在这里写下我自己的答案,因为我不确定其他人是否会解决这个问题。我怀疑的一件事是我最近将 C# 语言更新到 v7.3,因为 VS 2017 在编写一些代码时这么说。也许问题与此有关,但到目前为止,我的解决方案在最小化状态下工作。

我还想在这里声明,我首先实现了BackgroundTask 来克服这个问题,使用ApplicationTrigger 在需要时触发该过程,但老实说,这有点像黑客。看看代码:

public static async Task<string> GetBackgroundTaskReturnValue(string apiRequestUrl)
{
        StaticItemsHelper.IsBackgroundPlaylistTaskRunning = true;
        if (StaticItemsHelper.IsBackgroundPlaylistTaskRunning)
        {
            for (int seconds = 0; seconds < 20;)
            {
                if (!StaticItemsHelper.IsBackgroundPlaylistTaskRunning)
                {
                    break;
                }
                else
                {
                    Task.Delay(1000).Wait();
                }
            }
        }
        var request = BackgroundTaskHelper.BackgroundPlaylistTrigger.RequestAsync().GetResults();
        if (request == Windows.ApplicationModel.Background.ApplicationTriggerResult.Allowed)
        {
            SettingsHelper.localSettings.Values[SettingsHelper.BackgroundPlaylistPlaybackURLKey] = apiRequestUrl;
            SettingsHelper.localSettings.Values[SettingsHelper.BackgroundPlaylistPlaybackTokenKey] = StaticItemsHelper.CurrentUserAccessToken;
            if (SettingsHelper.tempFolder.TryGetItemAsync(SettingsHelper.BackgroundPlaylistPlaybackReturnKey).GetResults() is StorageFile file)
            {
                await file.DeleteAsync();
            }
            for (int seconds = 0; seconds < 30;)
            {
                if (SettingsHelper.tempFolder.TryGetItemAsync(SettingsHelper.BackgroundPlaylistPlaybackReturnKey).GetResults() is StorageFile _rfile)
                {
                    var _returnVal = FileIO.ReadTextAsync(_rfile).GetResults();
                    if (!string.IsNullOrEmpty(_returnVal.ToString()))
                    {
                        await _rfile.DeleteAsync();
                        SettingsHelper.localSettings.Values.Remove(SettingsHelper.BackgroundPlaylistPlaybackTokenKey);
                        SettingsHelper.localSettings.Values.Remove(SettingsHelper.BackgroundPlaylistPlaybackURLKey);
                        StaticItemsHelper.IsBackgroundPlaylistTaskRunning = false;
                        return _returnVal;
                    }
                }
                Task.Delay(2000).Wait();
                seconds += 2;
            }
        }
        else if (request == Windows.ApplicationModel.Background.ApplicationTriggerResult.CurrentlyRunning)
        {
            for (int seconds = 0; seconds < 30;)
            {
                Task.Delay(2000).Wait();
                seconds += 2;
                request = BackgroundTaskHelper.BackgroundPlaylistTrigger.RequestAsync().GetResults();
                if (request == Windows.ApplicationModel.Background.ApplicationTriggerResult.Allowed)
                {
                    return GetBackgroundTaskReturnValue(apiRequestUrl).Result;
                }
            }
        }
        if (SettingsHelper.tempFolder.TryGetItemAsync(SettingsHelper.BackgroundPlaylistPlaybackReturnKey).GetResults() is StorageFile _file)
        {
            await _file.DeleteAsync();
        }
        SettingsHelper.localSettings.Values.Remove(SettingsHelper.BackgroundPlaylistPlaybackTokenKey);
        SettingsHelper.localSettings.Values.Remove(SettingsHelper.BackgroundPlaylistPlaybackURLKey);
        StaticItemsHelper.IsBackgroundPlaylistTaskRunning = false;
        return "{ \"error\": {\"code\": \"NetworkError\", \"message\": \"Server returned nothing.\"} }";
}

实际解决方案: 但后来它也没有像我预期的那样工作,所以我决定放弃它并改用下面的代码。 (将此与问题进行比较)

public static async Task<string> GetResponseDataFromAPI(string apiRequestUrl, CancellationTokenSource cts = default)
{
        cts = cts ?? new CancellationTokenSource(TimeSpan.FromSeconds(20));
        try
        {
            if (StaticItemsHelper.IsAppInBackground)
            {
                //return await ViewHelper.GetBackgroundTaskReturnValue(apiRequestUrl);
                var responseData = AuthRequestHelper.globalHttpClient.GetAsync(apiRequestUrl, cts.Token).Result;
                var result = responseData.Content.ReadAsStringAsync().Result;
                return result;
            }
            else
            {
                var responseData = await AuthRequestHelper.globalHttpClient.GetAsync(apiRequestUrl, cts.Token);
                var result = await responseData.Content.ReadAsStringAsync();
                return result;
            }
        }
        catch (Exception ex)
        {
            INotifyHelper.iNotifyObject.IsDataLoading = false;
            // show error
            return "{ \"error\": {\"code\": " + $"\"{ex.HResult}\", \"message\": \"{ex.Message}\"" + "} }";
        }
}

希望这对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 2019-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多