maui
maui copied to clipboard
AndroidMessageHandler or HttpClientHandler throw System.ObjectDisposedException: Cannot access a closed Stream
Description
I am trying to do a local http post request from a http client but whenever I tried overriding to check the signed certificate by giving a HttpClientHandler or AndroidMessageHandler ot the http client, it ends up throwing an exception when I call to PostAsync method
Steps to Reproduce
Create a Maui Project On Program Add a HttpClient to the DI container
#if DEBUG
var httpHelper = new HttpClientHandlerHelper();
var insecureHandler =new CustomAndroidMessageHandler();//httpHelper.GetInsecureHandler()
builder.Services.AddSingleton<HttpClient>(x=> new HttpClient(httpHelper.GetInsecureHandler(), false));
#else
builder.Services.AddSingleton<HttpClient>();
#endif
declare a class to get the http client handler
HttpClientHandlerHelper
public class HttpClientHandlerHelper:IDisposable
{
private bool disposedValue;
public HttpClientHandler GetInsecureHandler()
{
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
return true;
};
return handler;
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: eliminar el estado administrado (objetos administrados)
}
// TODO: liberar los recursos no administrados (objetos no administrados) y reemplazar el finalizador
// TODO: establecer los campos grandes como NULL
disposedValue = true;
}
}
public void Dispose()
{
// No cambie este código. Coloque el código de limpieza en el método "Dispose(bool disposing)".
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
make some service using this HttpClient by DI and then call a method using PostAsync, but in the url the base url should contain the local ip in my case is like, while calling a webapi running
http://192.168.250.3:5000/api/Account/Create
Version with bug
6.0 Release Candidate 2 or older
Last version that worked well
Unknown/Other
Affected platforms
Android
Affected platform versions
API 30 Android 11, WIndows 10 1709
Did you find any workaround?
Not yet
Relevant log output
System.ObjectDisposedException: Cannot access a closed Stream.
at System.IO.MemoryStream.EnsureNotClosed()
at System.IO.MemoryStream.get_Length()
at System.Net.Http.HttpContent.GetComputedOrBufferLength()
at System.Net.Http.Headers.HttpContentHeaders.get_ContentLength()
at Xamarin.Android.Net.AndroidMessageHandler.SetupRequestBody(HttpURLConnection httpConnection, HttpRequestMessage request) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 1132
at Xamarin.Android.Net.AndroidMessageHandler.SetupRequestInternal(HttpRequestMessage request, URLConnection conn) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 984
at Xamarin.Android.Net.AndroidMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 374
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at MauiChat.Common.Services.ChatServicesService.CreateUser(String phoneNumber) in C:\Users\PontiacGTX\Source\Repos\MauiChat\Common\Services\ChatServicesService.cs:line 38}
Since you're registering as a singleton I'm guessing you're disposing of it and it keeps returning the disposed instance but need a sample to be sure.
Since you're registering as a singleton I'm guessing you're disposing of it and it keeps returning the disposed instance but need a sample to be sure.
ok try this repo https://github.com/PontiacGTX/MauiChat/tree/PontiacGTX-BRANCH
Since you're registering as a singleton I'm guessing you're disposing of it and it keeps returning the disposed instance but need a sample to be sure.
I have looking and I think if I could pass my own HttpMessageInvoker I could assign it to not be disposed https://github.com/dotnet/runtime/blob/4ff5a3a85a9b0de7ab9e9267959e668142815f4f/src/libraries/System.Net.Http/src/System/Net/Http/HttpMessageInvoker.cs#L124
https://microsoft.github.io/reverse-proxy/articles/http-client-config.html
Edit: also I tried instancing a new httpclient witout DI and it keep saying that it couldnt read on a disposed Stream
@PontiacGTX If you configure the HttpClient using AddTransient instead of AddSingleton, does the problem persist?
Hi @PontiacGTX. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
@PontiacGTX If you configure the HttpClient using AddTransient instead of AddSingleton, does the problem persist?
same exception using AndroidMessageHandler, somewhere it is disposing it or not reading to the end of the stream correctly or I dont know what else to think also I see AndroidMessageHandler has 1012 lines and the repository has like 330s
is there a difference I am using this legacy file? https://github.com/xamarin/xamarin-android/blob/6290a9c63251e7bbbb3a40ab5bdd230688267b85/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.Legacy.cs#L363
System.ObjectDisposedException: Cannot access a closed Stream. at System.IO.MemoryStream.EnsureNotClosed() at System.IO.MemoryStream.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at Xamarin.Android.Net.AndroidMessageHandler.WriteRequestContentToOutput(HttpRequestMessage request, HttpURLConnection httpConnection, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 458 at Xamarin.Android.Net.AndroidMessageHandler.DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken, RequestRedirectionState redirectState) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 533 at Xamarin.Android.Net.AndroidMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 375 at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at MauiChat.Common.HelperClass.HttpClientHelper.PostStringDataAsync(HttpClient httpClient, Object data, String url) in C:\Users\PontiacGTX\source\repos\MauiChat\Common\HelperClass\HttpClientHelper.cs:line 19 at MauiChat.Common.Services.ChatServicesService.CreateUser(String phoneNumber) in C:\Users\PontiacGTX\source\repos\MauiChat\Common\Services\ChatServicesService.cs:line 39}
@PontiacGTX does the endpoint you are posting to respond with a redirect?
Hi @PontiacGTX. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
@PontiacGTX does the endpoint you are posting to respond with a redirect?
no I have tried it with postman and returns Ok and then I see that it isnt being called with my debugger. I think IISExpress should be fine since I am doing a request from a local ip, curiously if the server has a timeout the the http client states it has time out but when reading the message it seems to have issues I will try again uninstalling my previous Android SDKs and see if that is the issue, or how can I use the latest version of AndroidClientHandler?
uninstalled all sdk except 30/31 android 11/12
and still the same exception using the default handler for android
System.ObjectDisposedException: Cannot access a closed Stream. at System.IO.MemoryStream.EnsureNotClosed() at System.IO.MemoryStream.CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken) at Xamarin.Android.Net.AndroidMessageHandler.WriteRequestContentToOutput(HttpRequestMessage request, HttpURLConnection httpConnection, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 458 at Xamarin.Android.Net.AndroidMessageHandler.DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken, RequestRedirectionState redirectState) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 533 at Xamarin.Android.Net.AndroidMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 375 at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at MauiChat.Common.HelperClass.HttpClientHelper.PostStringDataAsync(HttpClient httpClient, Object data, String url) in C:\Users\PontiacGTX\source\repos\MauiChat\Common\HelperClass\HttpClientHelper.cs:line 19 at MauiChat.Common.Services.ChatServicesService.CreateUser(String phoneNumber) in C:\Users\PontiacGTX\source\repos\MauiChat\Common\Services\ChatServicesService.cs:line 39}
using
{
HttpClientHandler handler = new();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
Console.WriteLine(message);
return true;
};
return handler;
}
returns
System.Net.WebException: Hostname 192.168.250.3 not verified: certificate: sha1/fVGKMV1jTGIwfF6V4Tb79pfSZ8Q= DN: CN=localhost subjectAltNames: [localhost] ---> Javax.Net.Ssl.SSLPeerUnverifiedException: Hostname 192.168.250.3 not verified: certificate: sha1/fVGKMV1jTGIwfF6V4Tb79pfSZ8Q= DN: CN=localhost subjectAltNames: [localhost] 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 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 at Javax.Net.Ssl.HttpsURLConnectionInvoker.Connect() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net6.0/android-31/mcw/Javax.Net.Ssl.HttpsURLConnection.cs:line 433 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 450 at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.<>c.<.cctor>b__272_0(Object obj) at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) --- End of stack trace from previous location --- at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) --- End of stack trace from previous location --- at Xamarin.Android.Net.AndroidMessageHandler.DoProcessRequest(HttpRequestMessage request, URL javaUrl, HttpURLConnection httpConnection, CancellationToken cancellationToken, RequestRedirectionState redirectState) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 502 at Xamarin.Android.Net.AndroidMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs:line 375 --- End of managed Javax.Net.Ssl.SSLPeerUnverifiedException stack trace --- javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.250.3 not verified: certificate: sha1/fVGKMV1jTGIwfF6V4Tb79pfSZ8Q= DN: CN=localhost subjectAltNames: [localhost] at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:205) at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:153) at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116) at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186) at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128) at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289) at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131) at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:90) at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:30)
--- End of managed Javax.Net.Ssl.SSLPeerUnverifiedException stack trace --- javax.net.ssl.SSLPeerUnverifiedException: Hostname 192.168.250.3 not verified: certificate: sha1/fVGKMV1jTGIwfF6V4Tb79pfSZ8Q= DN: CN=localhost subjectAltNames: [localhost] at com.android.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:205) at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:153) at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116) at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186) at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128) at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97) at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289) at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232) at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
similar issue to https://github.com/dotnet/runtime/issues/70434
Also seeing this issue. Only affects POST calls with content and the HttpClient is injected, we see this. If we use the same HttpClient for a get, or a post with no content, it works fine.
However, if we create a brand new Http client immediately before the call, it's fine.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
Also seeing this issue. Only affects POST calls with content and the HttpClient is injected, we see this. If we use the same HttpClient for a get, or a post with no content, it works fine.
However, if we create a brand new Http client immediately before the call, it's fine.
So what should I do is instancing a new http client before making a post?as a workaround?
This is what we had to do. It's not great, but at least it unblocked us.
public async Task AddAttendeeAsync(EventAttendee eventAttendee, CancellationToken cancellationToken = default) { try { var content = JsonContent.Create(eventAttendee, typeof(EventAttendee), null, SerializerOptions);
var authorizedHttpClient = HttpClientService.CreateAuthorizedClient();
var httpClient = new HttpClient();
httpClient.BaseAddress = authorizedHttpClient.BaseAddress;
using (var response = await httpClient.PostAsync(EventAttendeeApi, content, cancellationToken))
{
response.EnsureSuccessStatusCode();
}
}
catch (Exception ex)
{
Debug.WriteLine(@"\tERROR {0}", ex.Message);
throw;
}
}