Iraj
Iraj

Reputation: 389

How to download a list of files from AWS S3 with C# / .Net to my device?

I wish to download multiple images stored in S3. But for now it would be enough if I could download only one. I have the information of the paths of objects.

When I run the following code, I get this error:

Error encountered ***. Message:'Access Denied' when reading object ...

I first make an AmazonS3Client object based on my keys and access-config to connect to the server and then make a request based on storage path of my object and then somehow read the data and save it in my device.

By the way, in our AWS S3 we have “role”s, meaning that for downloading directly from S3 from the web platform my user in AWS is not enough to access to those objects, I should also change the role to the one which has access to those images after I log in.

using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using System;
using System.IO;
using System.Threading.Tasks;

namespace Amazon.DocSamples.S3
{
    class GetObjectTest
    {
        private const string bucketName = "My_Bucket_Name";
        private const string keyName = "123/456/789.jpg";
        // Specify your bucket region (an example region is shown).
        private static readonly RegionEndpoint bucketRegion = RegionEndpoint.USWest2;
        private static IAmazonS3 client;

        static string accessKey = "***AccessKey***";   // "YourAccessKeyHere";
        static string secretKey = "***SecretKey***"; 

        public static void Main()
        {
            client = new AmazonS3Client(accessKey,secretKey,bucketRegion);
            ReadObjectDataAsync().Wait();
        }

        static async Task ReadObjectDataAsync()
        {
            string responseBody = "";
            GetObjectRequest request = new GetObjectRequest
            {
                 BucketName = bucketName,
                 Key = keyName
            };
            using (GetObjectResponse response =     awaitclient.GetObjectAsync(request))
            using (Stream responseStream = response.ResponseStream)
            using (StreamReader reader = new StreamReader(responseStream))
            {
                string title = response.Metadata["x-amz-meta-title"]; // Assume you have "title" as medata added to the object.
                string contentType = response.Headers["Content-Type"];
                Console.WriteLine("Object metadata, Title: {0}", title);
                Console.WriteLine("Content type: {0}", contentType);

                responseBody = reader.ReadToEnd(); // Now you process the response body.
             }
        }
    }
}

I found the following link related to access problems: https://aws.amazon.com/premiumsupport/knowledge-center/s3-troubleshoot-403/

Upvotes: 2

Views: 7884

Answers (1)

Prayag Sagar
Prayag Sagar

Reputation: 671

I have modified your code a bit and was able to successfully execute a GetObjectAsync request.

using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using System.Drawing;
using System.Threading.Tasks;

namespace DownloadFromS3
{
    class GetObjectTest
    {
        private static IAmazonS3 client;

        private const string regionName = "us-west-2";
        private const string accessKey = "accessKey";
        private const string secretKey = "secretKey";
        private const string roleSessionName = "roleSessionName";
        private const string roleArn = "arn:aws:iam::123456789:role/yourRoleName";
        private const string bucketName = "bucketName";
        private const string keyName = "folder/keyName.jpg";

        public static void Main(string[] args)
        {
            var assumeRoleCredentials = FetchAssumeRoleCredentials();
            client = new AmazonS3Client(assumeRoleCredentials, RegionEndpoint.GetBySystemName(regionName));
            ReadObjectDataAsync().Wait();
        }

        static async Task ReadObjectDataAsync()
        {
            var request = new GetObjectRequest()
            {
                BucketName = bucketName,
                Key = keyName,
                ResponseHeaderOverrides = new ResponseHeaderOverrides
                {
                    ContentType = "image/jpg"
                }
            };

            using (var response = await client.GetObjectAsync(request))
            {
                using (var bitmap = new Bitmap(response.ResponseStream))
                {
                    bitmap.Save(@"C:\Image.jpg");
                }
            }
        }

        static Credentials FetchAssumeRoleCredentials()
        {
            var assumeRoleRequest = new AssumeRoleRequest
            {
                RoleSessionName = roleSessionName,
                RoleArn = roleArn
            };

            var securityTokenServiceClient = new AmazonSecurityTokenServiceClient(accessKey, secretKey, RegionEndpoint.GetBySystemName(regionName));
            var assumeRoleResponse = securityTokenServiceClient.AssumeRoleAsync(assumeRoleRequest).Result;
            return assumeRoleResponse.Credentials;
        }
    }
}

The code is more or less the same. What I suspect is

  • the regionName value being used AWS region code
  • AWS credentials being used not having enough permissions to read data from S3

Edit :

  1. Updated code to save the image locally. (Make sure to set the necessary write permissions)
  2. Updated code to create S3 Client using assumed role credentials. Your access key and secret key should have access to assume role and the assumed role should have access to S3 bucket.

Upvotes: 2

Related Questions