Search code examples
c#wpfdotnet-httpclient

C# HttpClient throws System.OutOfMemoryException over VPN


I have a WPF desktop application that consumes Web API over VPN. Relevant details:

  • App type: WPF
  • .NET: 4.6.2
  • OS: Windows 10
  • VPN: Palo Alto GlobalProtect

And sometimes it throws an uncaught exception from HttpClient on application start:

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)

here is relevant part of RestNetClient class implementation

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;
    }
<...>

The exception isn't caught in GetMyRoles method's catch clause and I get it in WPF's App.Dispatch.UnhandledException event handler. I'm calling this method from App.OnStartup method, like this:

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

I know that async void isn't the proper way to call async tasks, but I have to do some on startup, but my problem is with strange OutOfMemoryException thrown by HttpClient. If it does matter, return value of API call is a 4 byte integer, so I'm not trying to download 8K blue-rays and there is plenty of memory on a client.

Key observations:

  • exception is thrown occasionally
  • exception is thrown only at app startup (this particular API endpoint call which is called only once at startup)
  • if first call succeeds, then all subsequent API calls work as expected and never fail under normal conditions
  • issue reported by multiple clients and the only common thing is: they are connected to server over Palo Alto VPN client
  • issue never appear when client is connected directly to server (without VPN)
  • there are other applications on a client that communicate over same VPN and they doesn't seem have any connectivity issues over VPN.

Solution

  • finally, I was able to find and fix issue. Actual problem was here:

    Credentials = CredentialCache.DefaultNetworkCredentials
    

    It appears that HttpClient failed to read credential cache content (no idea on this). And fix was to replace that line with:

    UseDefaultCredentials = true
    

    and everything started to work correctly.