skip to Main Content

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.

3

Answers


  1. Chosen as BEST ANSWER

    So I finally found the solution and if you're a beginner like me on MAUI, I hope this helps.

    So my mistake came fundamentally from doing the API call in the Constructor. This hanged the app. The answers written before this are both correct solutions to the issue and helped me, together with r/dotnetMAUI, find my own answer.

    As a conclusion, don't call APIs in the Constructor, use functions such as OnCreate(), OnNavigatedTo() or OnAppearing() and override them.

    Happy coding :)


  2. 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.

    Login or Signup to reply.
  3. 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);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search