Repository navigation
AndroidMessageHandler disposes request MultipartFormDataContent inner JsonContent immediately after sending request #7086
Description
Activity
- addedArea: Mono.AndroidIssues with the Android API binding (Mono.Android.dll).Issues with the Android API binding (Mono.Android.dll).needs-triageIssues that need to be assigned.Issues that need to be assigned.
on Jun 10, 2022 - changed the title
[-]AndroidClientHandler getting disposed HttpRequestMessage.Content immediately after sending [/-][+]AndroidClientHandler disposes HttpRequestMessage.Content immediately after sending [/+]on Jun 10, 2022 - changed the title
[-]AndroidClientHandler disposes HttpRequestMessage.Content immediately after sending [/-][+]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent immediately after sending [/+]on Jun 14, 2022 - changed the title
[-]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent immediately after sending [/-][+]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent items immediately after sending [/+]on Jun 14, 2022 - changed the title
[-]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent items immediately after sending [/-][+]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent nested JsonContent item immediately after sending [/+]on Jun 14, 2022 - changed the title
[-]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent nested JsonContent item immediately after sending [/-][+]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent nested JsonContent item immediately after sending request[/+]on Jun 14, 2022 - changed the title
[-]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent nested JsonContent item immediately after sending request[/-][+]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent with nested JsonContent item immediately after sending request[/+]on Jun 14, 2022 - changed the title
[-]AndroidClientHandler disposes HttpRequestMessage MultipartFormDataContent with nested JsonContent item immediately after sending request[/-][+]AndroidMessageHandler disposes request MultipartFormDataContent inner JsonContent immediately after sending request[/+]on Jun 14, 2022 - removedneeds-triageIssues that need to be assigned.Issues that need to be assigned.
on Jun 14, 2022 - addedArea: HTTPIssues with sockets / HttpClient.Issues with sockets / HttpClient.and removedArea: Mono.AndroidIssues with the Android API binding (Mono.Android.dll).Issues with the Android API binding (Mono.Android.dll).
on Sep 6, 2022 @grendello this bug still exists in .NET 8 & the new
AndroidMessageHandlerand makes my app's logic way more complicated that it should be. I have a retry-logic for failed http requests and on iOS/macOS/Windows I can re-use theHttpContentfor multiple requests /HttpRequestMessages - except on Android.The exception can be very easily reproduced:
var jsonContent = JsonContent.Create("{}"); var request = new HttpRequestMessage(HttpMethod.Post, "https://httpbin.org/post") { Content = jsonContent }; _ = await new HttpClient().SendAsync(request); var contentValue = await jsonContent.ReadAsStringAsync();Ar there any plans to change this or is it "working as expected"?
@grendello @simonrozsival I believe the problem lies here:
https://github.com/xamarin/xamarin-android/blob/a82ac4e5608b9745916db320f4ff36921d4d6dee/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs#L539-L562- I believe the stream shouldn't be disposed of with a
usingblock, especially because the comment in it doesn't make much sense when doing so. Why is the stream rewound when it's disposed of right after? - Additionally, would it make sense to call the
ReadAsStreamAsyncoverload with a CancellationToken that was added with .NET? https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpcontent.readasstreamasync?view=net-8.0#system-net-http-httpcontent-readasstreamasync(system-threading-cancellationtoken)
Some background on why this fix would help me simplifying my apps' logic. I currently need to do something like this:
async Task<HttpResponseMessage> SendRequest(Func<HttpContent> contentFunc, int attempt = 1) { using var requestMessage = new HttpRequestMessage(HttpMethod.Post, "https://someurl.com") { Content = contentFunc.Invoke() }; var response = await httpClient.SendAsync(requestMessage); if (!response.IsSuccessStatusCode && attempt < 3) { await Task.Delay(2000 * attempt * attempt); return await SendRequest(contentFunc, attempt + 1); } return response; } await SendRequest(() => new ByteArrayContent(data));But I would prefer to use something like this (which works without issues on other platforms (iOS, macOS, Windows):
async Task<HttpResponseMessage> SendRequest(HttpContent content, int attempt = 1) { using var requestMessage = new HttpRequestMessage(HttpMethod.Post, "https://someurl.com") { Content = content }; var response = await httpClient.SendAsync(requestMessage); if (!response.IsSuccessStatusCode && attempt < 3) { await Task.Delay(2000 * attempt * attempt); return await SendRequest(content, attempt + 1); } return response; } await SendRequest(new ByteArrayContent(data));- I believe the stream shouldn't be disposed of with a
@tipa I can confirm that removing that
usingfixes this use-case. You're right that rewinding the stream just before disposing it seems weird.SocketsHttpHandlerdoesn't assume it owns the request message and it doesn't dispose the content. This code seems to be quite old (the rewinding was implemented in #608, theusingwas introduced even earlier in 0c35978).@grendello it seems that disposing the content stream is a bug, especially since the sockets handler doesn't do it.
Related: dotnet/macios#16341
@simonrozsival would you mind opening a PR? I can't even build
XAtoday, getting segfaults when building Mono.Android :(Reacted by Šimon RozsívalReacted by Marek Habersack- added a commit that references this issue
on Feb 27, 2024 - added a commit that references this issue
on Mar 11, 2024 - locked and limited conversation to collaborators
on Mar 29, 2024
Android application type
Classic Xamarin.Android (MonoAndroid12.0, etc.)
Affected platform version
VS for Mac 8.10.23 (build 7)
Description
AndroidMessageHandler disposes HttpContents buffered streams after request content was written to HttpConnection.OutputStream
Steps to Reproduce
Did you find any workaround?
Override AndroidClientHandler WriteRequestContentToOutput method. This allows us to prevent content buffered stream from disposing after writing to httpConnection.OutputStream:
AndroidClientHandler getting disposed HttpRequestMessage.Content immediately after sending
Relevant log output