1

I need to upload quite large files to my app in Azure (Linux, .Net Core 3.1, but also .Net 5.0 fails), but when uploading a file takes more than 2 minutes I get a TCP reset, showing the following error:

Unhandled exception. System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..

I looked through many posts with this error, but I do not see this scenario where the limit is 2 minutes and caused by the actual reading of the body stream. I already configured timeout - options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(20); - but it is not the request duration, it is when reading the stream in HttpProtocol takes longer than 2 minutes. In that case the middle ware is not even reached.

To reproduce I have a console app:

namespace TestUpload
{
public class DurationStream : Stream
{
    public DurationStream(TimeSpan duration)
    {
        // times 512 to prevent being kicked out because of too slow data
        Length = 512 * (int) duration.TotalSeconds;
        CanRead = true;
        CanWrite = false;
        CanSeek = false;
    }
    public override bool CanRead { get; }
    public override bool CanSeek { get; }
    public override bool CanWrite { get; }
    public override long Length { get; }
    public override long Position { get; set; }

    public override void Flush() { }

    public override int Read(byte[] buffer, int offset, int count)
    {
        var toCopy = Math.Min((int) (Length - Position), count);
        for (var i = 0; i < toCopy; ++i)
        {
            if (i % 512 == 0)
            {
                Thread.Sleep(TimeSpan.FromSeconds(1));
            }
            Position++;
        }
        return toCopy;
    }
    public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
    public override void SetLength(long value) { throw new NotImplementedException(); }
    public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
}

internal static class Program
{
    private static async Task Main()
    {
        var httpClient = new HttpClient();
        var request = new HttpRequestMessage(HttpMethod.Post, new Uri("http://[myazuresite.com]/upload"))
            {
                Content = new StreamContent(new DurationStream(TimeSpan.FromSeconds(130)))
            };
        var start = DateTime.Now;
        Console.WriteLine($"Started at {start}");
        try
        {
            await httpClient.SendAsync(request);
        }
        finally
        {
            Console.WriteLine($"Finished in {DateTime.Now - start}");
        }
    }
}

And then as controller:

[HttpPost]
public async Task Upload()
{
    await Request.Body.CopyToAsync(Stream.Null);            
}

Locally there is no problem running it against Kestrel, and also if I limit the upload to 2 minutes and after that sleep for a minute in the controller it works fine. The request fails after however long the upload is - so if the stream takes 5 minutes it fails after 5 minutes - and never reaches the middle ware. It fails with both http and https.

My hunch is that there is a network component in front of it in Azure that needs some acknowledgement within 2 minutes, but as it reads the whole stream before getting in the middle ware I do not see how to change the behavior. I did not see an easy way to inject a component in the internals of the Kestrel web server.

Suggestions anyone?

6
  • Don't upload a large file in a single request. Split it, then upload the pieces and rejoin them. Or just use Blob Storage. Commented Aug 13, 2021 at 8:48
  • Thanks, I thought of uploading chunks but it adds extra complexity for all clients of the API (and the server as well), the Blob storage lacks the more fine grained authorization that I enforce in the API. Commented Aug 13, 2021 at 8:57
  • Can you check TLS VERSION of azure app, hope this helps Link Commented Aug 13, 2021 at 9:35
  • The issue is both with http and https, so I guess it is not relevant, but minimum TLS is set to 1.2 Commented Aug 13, 2021 at 9:47
  • Does How do I set the request timeout for one controller action in an asp.net mvc application help? Commented Aug 13, 2021 at 11:28

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.