0

After making a lot of network requests in a short space of time, we keep getting "A task was canceled" error from our responses, once we start getting these errors any requests made after the errors stop return the same errors too until we restart the app. We use an AuthenticatedHttpClientHandler to handle auth tokens in our requests:

public class AuthenticatedHttpClientHandler : HttpClientHandler
{
    private readonly IReauthService _reauthService;

    public AuthenticatedHttpClientHandler(IReauthService reauthService)
    {
        _reauthService = reauthService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Url: " + request.RequestUri);

        var auth = request.Headers.Authorization;

        if (auth != null)
        {
            string token = await _reauthService.GetToken();

            request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);
        }

        try
        {
            //Error occurs on this line
            HttpResponseMessage resp = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

            return resp;
        }
        catch (Exception e)
        {
            //this.GetLogger().LogToDebugConsole("FAILED: " + request.Method + " " + request.RequestUri);
            //this.GetLogger().LogToDebugConsole("Reason: " + e.Message);
            //this.GetLogger().LogToDebugConsole("Stacktrace: " + e.StackTrace);

            Crashes.TrackError(e);

            throw new RequestFailedException(e);
        }
    }
}

We use this like so:

container.RegisterSingleton(() =>
        {
            var handler = container.Resolve<AuthenticatedHttpClientHandler>();

            HttpClient client = new HttpClient(handler)
            {
                BaseAddress = new Uri(UrlConfig.MobileApiBaseUrl + UrlConfig.Version),
                Timeout = TimeSpan.FromSeconds(30)
            };

            var service = RestService.For<IMobileApiClient>(client);
            return service;
        });

The 30s timeout is not the issue as all our requests are under 2s and we can reproduce the errors consistently.

A single HttpClient instance is used for every call. We also use MvvmCross and the issue appears to only be on iOS. We have tried changing the HttpClientImplementation in our project settings, as well using a new instance of HttpClient in every call but neither have worked.

Full Stacktrace:

==========A task was canceled.==========
==========  at System.Net.Http.MonoWebRequestHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x004ac] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/mcs/class/System.Net.Http/MonoWebRequestHandler.cs:507 
at CustomerApp.Core.Networking.LoggingAuthenticatedHttpClientHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x0059f] in /Users/user/VSProjects/CustomerApp/CustomerApp.Core/Networking/AuthenticatedHttpClientHandler.cs:38 ==========

Build settings:

enter image description here

MichaelStoddart
  • 5,571
  • 4
  • 27
  • 49
  • Looks like you are not using NSUrlSessionHandler. I highly suggest you use that instead of MonoWebRequestHandler. – Cheesebaron Jan 30 '20 at 15:52
  • @Cheesebaron i updated the question to show the build settings for our iOS project, I have NSUrlSession set as the HttpClientImplementation, am I missing something something else? – MichaelStoddart Jan 30 '20 at 15:55
  • 2
    Setting NSUrlSession in build settings is not respected, since you are providing your own handler! – Cheesebaron Jan 30 '20 at 15:55
  • @Cheesebaron We do our networking calls in the core project, is there a way of setting this without moving networking in to the Android and iOS projects? – MichaelStoddart Jan 30 '20 at 15:58
  • 3
    Well looks like you are already doing some Dependency Injection. You could create a interface, then implement it on each platform. Then have our wrapping handler be a `DelegatingHandler` instead which wraps the platform specific handler, which you inject. – Cheesebaron Jan 30 '20 at 16:02
  • > Setting NSUrlSession in build settings is not respected, since you are providing your own handler! @Cheesebaron, would this also be the case if you were to instantiate an HttpClient with `new HttpClient(new HttpClientHandler())`? – Kyle Jan 31 '20 at 19:25
  • 1
    Yes, you will need to specifically use the NSUrlSessionHandler and AndroidClientHandler when explicitly creating a instance of HttpClieny where you pass in a handler – Cheesebaron Jan 31 '20 at 20:43

0 Answers0