I'm occasionally seeing a System.ObjectDisposedException
when trying to make a POST request with a StreamContent
as the file type. I saw this once or twice last week, but was unable to repro, but a teammate is hitting this error consistently. Here's the code in question. I've simplified it a bit, but made sure to keep the same structure as the code that we have:
async Task ThisMethodThrows()
{
string filePath = "foo.file";
await ExecuteAndIgnoreFileInUseException(() =>
{
using (FileStream filestream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
return this.client.UploadFile(filestream);
}
});
}
// We have to do this a lot, so there's a common method to avoid needing to copy this bulky try-catch and HResult everywhere
static async Task ExecuteAndIgnoreFileInUseException(Func<Task> func)
{
try
{
await func();
}
catch (Exception)
{
if (ex.HResult != -2146233088) // This HResult indicates file is in use
{
throw;
}
}
}
// Code in this.client from above:
private readonly HttpClient inner;
public Client()
{
this.inner = new HttpClient();
// other misc setup...
}
async Task UploadFile(Stream stream)
{
using (HttpRequestMessage message = new HttpRequestMessage())
{
message.Method = HttpMethod.Post;
message.Content = new StreamContent(stream);
message.RequestUri = new Uri("http://foo.com/bar");
HttpResponseMessage response = await this.inner.SendAsync(message);
// error handling...
}
}
We recently moved ThisMethodThrows
and ExecuteAndIgnoreFileInUseException
to use an asynchronous pattern since previously they were just using .Wait()
on the async client methods, but now we're seeing what appears to be a race condition with the files and disposing and all that. My best guess right now is that the lambda function is returning the Task
for this.client.UploadFile
very quickly, and then the stream is getting disposed before the work is actually done. Do we need to make the lambda async and await that call within it to avoid this issue? What's the proper way to "async-ify" this code?