Closed PontiacGTX closed 10 months ago
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.
@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.
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.
--- 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;
}
}
I suspect I have the same problem as the OP, given I'm also using a CustomAndroidMessageHandler
to override the hostname verification and certificate, and I'm also using an IP address and HTTP http://192.168.2.127:5241/api/v1/Login
.
HttpClient throws the same exception if my server redirects http to https, but if I turn that off without touching the MAUI app, it works.
I am injecting HttpClient as a singleton, using AddTransient
makes no difference to the exception:
builder.Services
//... other services ...
.AddSingleton<HttpsClientHandlerService>()
.AddSingleton<HttpClient>(provider =>
{
var handler = provider.GetService<HttpsClientHandlerService>();
if (handler == null)
{
return new HttpClient();
}
else
{
return new HttpClient(handler.GetPlatformMessageHandler());
}
})
HttpsClientHandlerService handles both hostname and certificate:
public class HttpsClientHandlerService
{
public HttpMessageHandler GetPlatformMessageHandler()
{
#if ANDROID
var handler = new CustomAndroidMessageHandler();
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
if (cert != null && cert.Issuer.Equals("CN=localhost"))
return true;
return errors == System.Net.Security.SslPolicyErrors.None;
};
return handler;
#elif IOS
var handler = new NSUrlSessionHandler
{
TrustOverrideForUrl = IsHttpsLocalhost
};
return handler;
#else
throw new PlatformNotSupportedException("Only Android and iOS supported.");
#endif
}
#if ANDROID
internal sealed class CustomAndroidMessageHandler : Xamarin.Android.Net.AndroidMessageHandler
{
protected override Javax.Net.Ssl.IHostnameVerifier GetSSLHostnameVerifier(Javax.Net.Ssl.HttpsURLConnection connection)
=> new CustomHostnameVerifier();
private sealed class CustomHostnameVerifier : Java.Lang.Object, Javax.Net.Ssl.IHostnameVerifier
{
public bool Verify(string hostname, Javax.Net.Ssl.ISSLSession session)
{
return Javax.Net.Ssl.HttpsURLConnection.DefaultHostnameVerifier.Verify(hostname, session) ||
((hostname == "10.0.2.2" || hostname == "192.168.2.127") && session.PeerPrincipal?.Name == "CN=localhost");
}
}
}
#elif IOS
public bool IsHttpsLocalhost(NSUrlSessionHandler sender, string url, Security.SecTrust trust)
{
if (url.StartsWith("https://localhost"))
return true;
return false;
}
#endif
}
The server is a .NET Core 6 api using
var app = builder.Build();
// ...
app.UseHttpsRedirection(); //
commenting out that last app.UseHttpsRedirection();
on the server makes the MAUI client connect without exception.
@hartez @joebeernink @thinkOfaNumber @PureWeen
So I had actually followed the solution that I had to create a http client based off a message handler either for HttpClient or an Android Handler, but the problem was that the service where the HttpClient was being injected was a Transient one, and the HttpClient was a Singleton, so I fixed the issue by using a Scoped service then to inject a HttpClient as Singleton , so the HttpClient´s Message hander is being Disposed before the response has been read, so I wonder if this would be a bug for the DI container or maybe a misuse from my part?
I am facing the same issue in .net8 rc1 without using the DI.
builder.Services.AddSingleton<IFileDownloadService, FileDownloadService>();
public class FileDownloadService : IFileDownloadService
{
private readonly HttpClient client;
public FileDownloadService()
{
//DEBUG
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback += (sender, certificate, chain, errors) => true;
client = new(httpClientHandler);
}
public async Task<FileDownloadResponse> DownloadFileAsync(){..}
}
The only way it works in .net 8 is to define the httpClient in the DownloadFileAsync function instead of the constructor.
public async Task<FileDownloadResponse> DownloadFileAsync()
{
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback += (sender, certificate, chain, errors) => true;
client = new(httpClientHandler);
....
}
Switching back to net7 solves the issue. I guess this is something with .net8 rc.
Tagging subscribers to this area: @dotnet/ncl See info in area-owners.md if you want to be subscribed.
Author: | PontiacGTX |
---|---|
Assignees: | - |
Labels: | `area-System.Net.Http`, `untriaged` |
Milestone: | - |
Tagging subscribers to 'arch-android': @steveisok, @akoeplinger See info in area-owners.md if you want to be subscribed.
Author: | PontiacGTX |
---|---|
Assignees: | - |
Labels: | `area-System.Net.Http`, `os-android`, `untriaged` |
Milestone: | - |
AFAIK HttpClientHandler
will use platform handler if you target Maui. You would need to use SocketsHttphandler
explicitly if you want to use the managed implementation.
cc: @simonrozsival for more comments.
@wfurt Yes, the native handler is used by default (in case of Android that is AndroidMessageHandler
). It's possible to either create SocketsHttpHandler
manually and pass it to HttpClient
or the developer can add <UseNativeHttpHandler>false</UseNativeHttpHandler>
to change the default behavior.
The original issue used ServerCertificateCustomValidationCallback
in .NET 6. At that time this functionality wasn't properly implemented in either the native nor the managed HTTP handlers. The native handler supports the validation callback since .NET 7 and the managed one since .NET 8.
@arahmancsd I'm surprised there is a difference between .NET 7 and .NET 8 RC1. Have you tried again with the final release of .NET 8? Can you still reproduce the issue?
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
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