Home > Net >  C# MAUI Async function catches for Windows but not for Android
C# MAUI Async function catches for Windows but not for Android

Time:02-05

I have the following code:

public partial class MetricsPage : ContentPage
{
    public MetricsPage()
    {
        InitializeComponent();
        using var client = new HttpClient();
        client.BaseAddress = new Uri("http://example.com");
        client.Timeout = new TimeSpan(0, 0, 3);
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Api-Key", "<my_key>");
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

        totalCreatedThings.Text = GetNumberOfThingsAsync(client).GetAwaiter().GetResult();
    }

    static async Task<string> GetNumberOfThingsAsync(HttpClient client)
    {
        try
        {
            HttpResponseMessage response = await client.GetAsync("/api/get_number_things").ConfigureAwait(false);

            if (response.IsSuccessStatusCode)
            {
                string numberOfThings = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                return numberOfThings;
            }
            else
            {
                return string.Empty;
            }
        }
        catch (HttpRequestException hex)
        {
            System.Diagnostics.Debug.WriteLine(hex.Message);
            return string.Empty;
        }
        catch (OperationCanceledException oex)
        {
            System.Diagnostics.Debug.WriteLine(oex.Message);
            return string.Empty;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
            return string.Empty;
        }
    }
}

For this code and when debugging with the Windows Machine in Visual Studio 2022, errors in GetNumberOfThingsAsync are catched correctly. These errors consist on a failed request to the api. However, when executing this exact same code in Android, errors are not catched and the following error is shown instead:

System.Threading.Tasks.TaskCanceledException: 'The request was canceled due to the configured HttpClient.Timeout of 3 seconds elapsing.'

And the output is:

[monodroid-net] Exception caught while cancelling connection: Java.Net.SocketException: Socket closed
[monodroid-net]    at Java.Interop.JniEnvironment.InstanceMethods.CallVoidMethod(JniObjectReference instance, JniMethodInfo method, JniArgumentValue* args) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.g.cs:line 11884
[monodroid-net]    at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod(String encodedMember, IJavaPeerable self, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:line 17
[monodroid-net]    at Java.Net.HttpURLConnectionInvoker.Connect() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-31/mcw/Java.Net.HttpURLConnection.cs:line 725
[monodroid-net]    at Xamarin.Android.Net.AndroidMessageHandler.<>c__DisplayClass125_0.<ConnectAsync>b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 444
[monodroid-net]   --- End of managed Java.Net.SocketException stack trace ---
[monodroid-net] java.net.SocketException: Socket closed
[monodroid-net]     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:394)
[monodroid-net]     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
[monodroid-net]     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
[monodroid-net]     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
[monodroid-net]     at java.net.Socket.connect(Socket.java:646)
[monodroid-net]     at com.android.okhttp.internal.Platform.connectSocket(Platform.java:182)
[monodroid-net]     at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:145)
[monodroid-net]     at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
[monodroid-net]     at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
[monodroid-net]     at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
[monodroid-net]     at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
[monodroid-net]     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
[monodroid-net]     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
[monodroid-net]     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
[monodroid-net]     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
[monodroid-net] 
[monodroid-net]   --- End of managed Java.Net.SocketException stack trace ---
[monodroid-net] java.net.SocketException: Socket closed
[monodroid-net]     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:394)
[monodroid-net]     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
[monodroid-net]     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
[monodroid-net]     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
[monodroid-net]     at java.net.Socket.connect(Socket.java:646)
[monodroid-net]     at com.android.okhttp.internal.Platform.connectSocket(Platform.java:182)
[monodroid-net]     at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:145)
[monodroid-net]     at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
[monodroid-net]     at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
[monodroid-net]     at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
[monodroid-net]     at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
[monodroid-net]     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
[monodroid-net]     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
[monodroid-net]     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
[monodroid-net]     at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
[monodroid-net] 
**System.Threading.Tasks.TaskCanceledException:** 'The request was canceled due to the configured HttpClient.Timeout of 3 seconds elapsing.'

Errors in the request must be catched both for the Windows Machine and for Android.

CodePudding user response:

If your issue is the debugger is not working this might help.

Add this in on create method in android main activity.

  protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        AppDomain.CurrentDomain.UnhandledException  = CurrentDomain_UnhandledException;
       
    }
    private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    { System.Diagnostics.Debug.WriteLine(e.ToString()); }

Try adding that and make sure JIT debugger is enabled and you can get it working maybe? I used the above and it works for me. Not sure if it will help you do what you want. At least it might help with debugging it.

CodePudding user response:

Due to the Socket closed error message I suspect that chances are that your HttpClient instance is disposed before your HTTP request could have been completed.

I would suggest moving your HTTP request from the .ctor.

E.g., you can override the OnNavigatedTo() method that can be an async method.

protected override async void OnNavigatedTo(NavigatedToEventArgs args)
{
    using var client = new HttpClient();

    client.BaseAddress = new Uri("http://example.com");
    client.Timeout = new TimeSpan(0, 0, 3);

    client.DefaultRequestHeaders.Authorization =
        new AuthenticationHeaderValue("Api-Key", "<my_key>");

    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue(
            System.Net.Mime.MediaTypeNames.Application.Json
        )
    );

    totalCreatedThings.Text = await GetNumberOfThingsAsync(client);
}
  • Related