I'm downloading a file as a stream with httpClient.SendAsync() and on cancellation with CancellationToken I get a java.net.SocketException: Socket closed exception every time. Full stack trace:
[monodroid] Not wrapping exception of type Java.Net.SocketException from method `SendAsync`. This will change in a future release.
[0:] at Java.Interop.JniEnvironment+InstanceMethods.CallIntMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00068] in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.g.cs:11725
at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualInt32Method (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00024] in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods_Invoke.cs:229
at Java.Net.HttpURLConnection.get_ResponseCode () [0x00000] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/monoandroid10/android-31/mcw/Java.Net.HttpURLConnection.cs:511
at Xamarin.Android.Net.AndroidClientHandler+<>c__DisplayClass46_0.<DoProcessRequest>b__2 () [0x00000] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.Legacy.cs:438
at System.Threading.Tasks.Task`1[TResult].InnerInvoke () [0x0000f] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs:534
at System.Threading.Tasks.Task.Execute () [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corert/src/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs:2319
--- End of stack trace from previous location where exception was thrown ---
at Xamarin.Android.Net.AndroidClientHandler.DoProcessRequest (System.Net.Http.HttpRequestMessage request, Java.Net.URL javaUrl, Java.Net.HttpURLConnection httpConnection, System.Threading.CancellationToken cancellationToken, Xamarin.Android.Net.AndroidClientHandler+RequestRedirectionState redirectState) [0x00328] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.Legacy.cs:438
at Xamarin.Android.Net.AndroidClientHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x00286] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.Legacy.cs:287
at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506
at TestHttpClientSocketException.MainPage.startButton_Clicked (System.Object sender, System.EventArgs e) [0x00113] in C:\Projects\TestHttpClientSocketException\TestHttpClientSocketException\TestHttpClientSocketException\MainPage.xaml.cs:43
--- End of managed Java.Net.SocketException stack trace ---
java.net.SocketException: Socket closed
at java.net.SocketInputStream.read(SocketInputStream.java:203)
at java.net.SocketInputStream.read(SocketInputStream.java:139)
at com.android.okhttp.okio.Okio$2.read(Okio.java:141)
at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:316)
at com.android.okhttp.okio.RealBufferedSource.indexOf(RealBufferedSource.java:310)
at com.android.okhttp.okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:206)
at com.android.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:395)
at com.android.okhttp.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:144)
at com.android.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:887)
at com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:759)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:499)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:435)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:566)
If it is a OperationCanceledException or something like that then everything would be ok, but I don't open or close a socket manually. It's done by the underlying libraries (I use Android for the HttpClient implementation). In the following a minimal example can be found.
XAML:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestHttpClientSocketException.MainPage">
<StackLayout>
<Button x:Name="startButton" Text="Download" Clicked="startButton_Clicked" />
<Button x:Name="cancelButton" Text="Cancel" Clicked="cancelButton_Clicked" />
</StackLayout>
</ContentPage>
Code behind:
public partial class MainPage : ContentPage
{
CancellationTokenSource cancelToken;
public MainPage()
{
InitializeComponent();
this.cancelToken = new CancellationTokenSource();
}
private async void startButton_Clicked(object sender, EventArgs e)
{
HttpResponseMessage response;
try
{
using (var httpClient = new HttpClient())
{
HttpMethod method = HttpMethod.Post;
string requestUri = "http://0.0.0.0:80/some/uri";
httpClient.Timeout = new TimeSpan(0, 0, 300);
HttpContent httpContent = new StringContent("<soapenv:Envelope ...");
HttpRequestMessage req = new HttpRequestMessage(method, requestUri);
req.Headers.Add("SOAPAction", "http://schemas.xmlsoap.org/soap/envelope");
req.Method = method;
req.Content = httpContent;
req.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/xml" + "; charset=utf-8");
response = await httpClient.SendAsync(req, this.cancelToken.Token).ConfigureAwait(false);
System.Diagnostics.Debug.WriteLine("finished");
}
} catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.StackTrace);
}
}
private void cancelButton_Clicked(object sender, EventArgs e)
{
this.cancelToken.Cancel();
this.cancelToken = new CancellationTokenSource();
}
}
Why I'm getting a SocketException and how should I handle this? Should I ignore it? Am I doing something wrong?