【问题标题】:C# HttpClient throws System.OutOfMemoryException over VPNC# HttpClient 通过 VPN 引发 System.OutOfMemoryException
【发布时间】:2021-04-22 10:32:53
【问题描述】:

我有一个 WPF 桌面应用程序,它通过 VPN 使用 Web API。相关细节:

  • 应用类型:WPF
  • .NET:4.6.2
  • 操作系统:Windows 10
  • VPN:帕洛阿尔托 GlobalProtect

有时它会在应用程序启动时从 HttpClient 抛出未捕获的异常:

Error message: Exception of type 'System.OutOfMemoryException' was thrown.
Stack trace:
    at MyApp.Net.Services.RestNetClient.<GetMyRoles>d__5.MoveNext()
    at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
    at MyApp.Net.Services.RestNetClient.GetMyRoles()
<...>
--- End of stack trace from previous location where exception was thrown ---
        at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
        at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
        at MyApp.Wpf.UI.App.<OnStartup>d__3.MoveNext() in  <...>\App.xaml.cs:line 44
--- End of stack trace from previous location where exception was thrown ---
        at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
        at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
        at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

这是RestNetClient类实现的相关部分

public class RestNetClient : INetClient {
    public RestNetClient(IRemoteConfig config) {
        if (Client == null) {
            HttpClientHandler authHandler = new HttpClientHandler {
                Credentials = CredentialCache.DefaultNetworkCredentials
            };
            Client = new HttpClient(authHandler) { BaseAddress = config.ServerAddress };
            Client.DefaultRequestHeaders.Accept.Clear();
            Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }
    }

    protected static HttpClient Client { get; private set; }

    public async Task<IServiceOperationResult<AppRole>> GetMyRoles() {
        var result = new ServiceOperationResult<AppRole>();
        try {

            HttpResponseMessage response = await Client.GetAsync("api/ntds/getmyroles");
            if (response.IsSuccessStatusCode) {
                String json = await response.Content.ReadAsStringAsync();
                result.Value = JsonConvert.DeserializeObject<AppRole>(json);
            } else {
                await response.SetErrorCode(result);
            }
        } catch (Exception ex) {
            result.HResult = ErrorCode.E_INVALIDARG;
            result.ErrorMessage = ex.Message;
        }

        return result;
    }
<...>

GetMyRoles 方法的 catch 子句中没有捕获异常,我在 WPF 的 App.Dispatch.UnhandledException 事件处理程序中得到它。我从App.OnStartup方法调用这个方法,像这样:

protected override async void OnStartup(StartupEventArgs e) {
    <...>
    var result = await restClient.GetMyroles();
    <...>
}

我知道async void 不是调用异步任务的正确方法,但我必须在启动时做一些事情,但我的问题是HttpClient 抛出的奇怪OutOfMemoryException。如果它确实重要,API 调用的返回值是一个 4 字节整数,所以我不会尝试下载 8K 蓝光并且客户端上有足够的内存。

主要观察:

  • 偶尔会抛出异常
  • 仅在应用启动时引发异常(此特定 API 端点调用仅在启动时调用一次)
  • 如果第一次调用成功,那么所有后续 API 调用都会按预期工作,并且在正常情况下永远不会失败
  • 多个客户端报告的问题,唯一常见的是:它们通过 Palo Alto VPN 客户端连接到服务器
  • 当客户端直接连接到服务器(没有 VPN)时,问题永远不会出现
  • 客户端上还有其他应用程序通过相同的 VPN 进行通信,它们似乎没有任何通过 VPN 的连接问题。

【问题讨论】:

  • 请注意,您是否考虑过用异步启动事件处理程序替换异步 OnStartup 覆盖,这将是使用 async void 的正确方法?
  • @Clemens 在同一个 App.xaml.cs 文件中?我可以,只要有理由这样做。不过,我不知道我的情况会发生什么变化。
  • 是的,完全正确。它不会解决您的问题,但会使 async void 声明“正确”。
  • @Clemens 好的,我会考虑的。
  • 提示HttpResponseMessageIDisposable。添加using

标签: c# wpf dotnet-httpclient


【解决方案1】:

最后,我能够找到并解决问题。实际问题在这里:

Credentials = CredentialCache.DefaultNetworkCredentials

似乎 HttpClient 未能读取凭证缓存内容(对此不知道)。解决方法是将该行替换为:

UseDefaultCredentials = true

一切都开始正常工作了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 2011-06-23
    • 2012-07-06
    • 2011-10-10
    相关资源
    最近更新 更多