PutFile using stream does not upload whole file with S3 object stream

Advertisement

obrynda
Joined:
Posts:
2

PutFile using stream does not upload whole file with S3 object stream

Hey, I am trying to use WinSCP NuGet package version 6.5.3 to upload file to FTP server. I have a file stored in AWS S3 and I wanted to use stream variant of PutFile for upload. Problem is that only 17kB out of 10MB are uploaded. It works fine when I copy S3 stream to memory stream first, or if I use temporary file variant PutFiles. Is there a something I am doing wrong? I would expect S3 stream to be like any other stream – it has no problem writing it to file etc.
Thank you for checking.
Here's minimal example and I am also attaching logs for all variants I tested.
using Amazon.S3;
using Amazon.S3.Model;
using WinSCP;
using Protocol = WinSCP.Protocol;
 
namespace ConsoleApp1;
 
class Program
{
    private const string ServerUrl = "updateMe";
    private const string Username = "updateMe";
    private const string Password = "updateMe";
    private const string Destination = "updateMe";
 
    private const string S3Bucket = "updateMe";
    private const string S3File = "updateMe";
 
    private static readonly AmazonS3Client AmazonS3Client = new ();
 
    static void Main()
    {
        // doesn't upload whole file - only 17kb
        UploadUsingS3Stream().Wait();
 
        // uploads whole file
        UploadUsingMemoryStream().Wait();
 
        // uploads whole file
        UploadUsingFile().Wait();
    }
 
    static async Task UploadUsingS3Stream()
    {
        using var session = new Session();
        session.SessionLogPath = "UploadUsingS3Stream.log";
 
        session.Open(new SessionOptions
        {
            Protocol = Protocol.Ftp,
            HostName = ServerUrl,
            PortNumber = 21,
            FtpMode = FtpMode.Passive,
            UserName = Username,
            Password = Password
        });
 
        var s3Response = await AmazonS3Client.GetObjectAsync(new GetObjectRequest
        {
            Key = S3File,
            BucketName = S3Bucket
        });
 
        session.PutFile(
            s3Response.ResponseStream, // using S3 stream directly
            Destination + $"/{Guid.NewGuid()}.txt",
            new TransferOptions
            {
                TransferMode = TransferMode.Binary,
                PreserveTimestamp = false,
                OverwriteMode = OverwriteMode.Overwrite
            });
    }
 
    static async Task UploadUsingMemoryStream()
    {
        using var session = new Session();
        session.SessionLogPath = "UploadUsingMemoryStream.log";
 
        session.Open(new SessionOptions
        {
            Protocol = Protocol.Ftp,
            HostName = ServerUrl,
            PortNumber = 21,
            FtpMode = FtpMode.Passive,
            UserName = Username,
            Password = Password
        });
 
        var s3Response = await AmazonS3Client.GetObjectAsync(new GetObjectRequest
        {
            Key = S3File,
            BucketName = S3Bucket
        });
 
        // copy to memory stream
        var memoryStream = new MemoryStream();
        await s3Response.ResponseStream.CopyToAsync(memoryStream);
        memoryStream.Position = 0;
 
        session.PutFile(
            memoryStream, // using stream copied to memory stream
            Destination + $"/{Guid.NewGuid()}.txt",
            new TransferOptions
            {
                TransferMode = TransferMode.Binary,
                PreserveTimestamp = false,
                OverwriteMode = OverwriteMode.Overwrite
            });
    }
 
    static async Task UploadUsingFile()
    {
        using var session = new Session();
        session.SessionLogPath = "UploadUsingFile.log";
 
        session.Open(new SessionOptions
        {
            Protocol = Protocol.Ftp,
            HostName = ServerUrl,
            PortNumber = 21,
            FtpMode = FtpMode.Passive,
            UserName = Username,
            Password = Password
        });
 
        var s3Response = await AmazonS3Client.GetObjectAsync(new GetObjectRequest
        {
            Key = S3File,
            BucketName = S3Bucket
        });
 
        // copying to temporary file first
        var tempPath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
        await using var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write);
        await s3Response.ResponseStream.CopyToAsync(fileStream);
 
        var result = session.PutFiles(
            tempPath, // using file path
            Destination + $"/{Guid.NewGuid()}.txt",
            false,
            new TransferOptions
            {
                TransferMode = TransferMode.Binary,
                PreserveTimestamp = false,
                OverwriteMode = OverwriteMode.Overwrite
            });
 
        result.Check();
    }
}
  • logs.zip (7.49 KB, Private file)

Reply with quote

Advertisement

martin
Site Admin
martin avatar
Joined:
Posts:
42,276
Location:
Prague, Czechia

Re: PutFile using stream does not upload whole file with S3 object stream

Thanks for your report.
I'll look into it. But it might take some time.
Meanwhile, did you try using non-async AmazonS3Client.GetObject?

Reply with quote

obrynda

Great, thank you for looking into it.
I tried to use non-async AmazonS3Client.GetObject (it's internal method, so by using reflection) but result is the same – only 17kB uploaded.

Reply with quote

Advertisement

You can post new topics in this forum