Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# MVC/API - Return an image from Amazon S3 for my API Call

I'm using .net core to upload and retrieve an image from a private Amazon S3 bucket.

I'm able to upload it successfully, and even view it after I download it from S3, however when I'm a bit unsure about how to return the stream/response back to the client for the actual API call (for example right now I'm just trying to use Postman/Fiddler proxy tools to get back the image from my API)

My code for S3 to retrieve the stream:

///Retrieve my image from my bucket

public async Task<string> ReadObjectData(MediaFolder key, String fileName)
    {
        string responseBody = "";
        IAmazonS3 client;

        using (client = new AmazonS3Client(accessKey, accessSecret, endpoint))
        {
            Amazon.S3.Model.GetObjectRequest request = new Amazon.S3.Model.GetObjectRequest
            {
                BucketName = bucket,
                Key = key + "/" + fileName,
            };
            using (GetObjectResponse response = await client.GetObjectAsync(request))
            using (Stream responseStream = response.ResponseStream)
            using (StreamReader reader = new StreamReader(responseStream))
            {
                string title = response.Metadata["x-amz-meta-title"];
                responseBody = reader.ReadToEnd();
            }
        }
         return responseBody;
    }

So now in my controller, I have the following action:

   [HttpGet("ProfilePic")]
    public async Task<IActionResult> GetProfilePicture()
    {
        var user = await GetUserFromBearerToken();

        //Retrieve
        var utf8ImageResponse = await _fileService.ReadObjectData(MediaFolder.Profiles, user.ProfileImageFileName);

        //To return a file as a stream
        var imageBytes = System.Text.Encoding.UTF8.GetBytes(utf8ImageResponse);

        //Return the image, which I'll hardcode as jpeg for a test
        return File(imageBytes, "image/jpeg");
    }

When I make the call using Postman, it returns a little blank box (the box you'd see if you tried to return an image, but it wasn't a valid image or null in some way).

Right now I'm using Postman but ideally I'd want an app to present this image.

Any ideas what I'm doing wrong? I tried messing around with base64 encoding and other things but nothing seems to work.

Thanks!

like image 766
NullHypothesis Avatar asked Sep 19 '18 18:09

NullHypothesis


1 Answers

This way you can retrieve the file as stream from S3 storage

public async Task<Stream> ReadObjectData(MediaFolder key, String fileName)
{
    try
    {
        using (var client = new AmazonS3Client(accessKey, accessSecret, endpoint))
        {
            var request = new GetObjectRequest
            {
                BucketName = bucket,
                Key = key + "/" + fileName
            };

            using (var getObjectResponse = await client.GetObjectAsync(request))
            {
                using (var responseStream = getObjectResponse.ResponseStream)
                {
                    var stream = new MemoryStream();
                    await responseStream.CopyToAsync(stream);
                    stream.Position = 0;
                    return stream;
                }
            }
        }
    }
    catch (Exception exception)
    {
        throw new Exception("Read object operation failed.", exception);
    }
}

And then - return this stream as FileStreamResult:

[HttpGet("ProfilePic")]
public async Task<IActionResult> GetProfilePicture()
{
    var user = await GetUserFromBearerToken();

    Stream imageStream = await _fileService.ReadObjectData(MediaFolder.Profiles, user.ProfileImageFileName);

    Response.Headers.Add("Content-Disposition", new ContentDisposition
    {
        FileName = "Image.jpg",
        Inline = true // false = prompt the user for downloading; true = browser to try to show the file inline
    }.ToString());

    return File(imageStream, "image/jpeg");
}
like image 83
Dmitry Pavlov Avatar answered Sep 30 '22 00:09

Dmitry Pavlov