2

So currently my code uploads an image to S3 but what I want it to now do is to get the URL of the image that has been uploaded, so this URL can be stored in the DB and used later.

I know it's possible, as it was shown in this question here: s3 file upload does not return response (but that is JavaScript and I'm struggling to convert it to c#)

This is my code, it works perfectly, I just need to get the URL of the uploaded object + is there a way to make the object public by default. I tried to console write the response but that was no help

public class AmazonS3Uploader
{

    private string bucketName = "cartalkio-image-storage-dev";
    private string keyName = DateTime.Now.ToString() + ".png";


    public async void UploadFile()
    {
        byte[] bytes = System.Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");

        Stream stream = new MemoryStream(bytes);

        var myAwsAccesskey = "*************";
        var myAwsSecret = "**************************";

        var client = new AmazonS3Client(myAwsAccesskey, myAwsSecret, Amazon.RegionEndpoint.EUWest2);

        try
        {
            PutObjectRequest putRequest = new PutObjectRequest
            {
                BucketName = bucketName,
                Key = keyName,
                ContentType = "image/png",
                InputStream = stream
            };

            PutObjectResponse response = await client.PutObjectAsync(putRequest);

        // Console.Write(response);
        }
        catch (AmazonS3Exception amazonS3Exception)
        {
            if (amazonS3Exception.ErrorCode != null &&
                (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId")
                ||
                amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))
            {
                throw new Exception("Check the provided AWS Credentials.");
            }
            else
            {
                throw new Exception("Error occurred: " + amazonS3Exception.Message);
            }
        }
    }
chumberjosh
  • 400
  • 5
  • 19

1 Answers1

4

I've searched the documentation and various websites but this was all I found () - I guess there just isn't a URL that is returned. What I've done is changed my code around a bit because you can always predict what the object URL will be based on the name of the object you're uploading. i.e if you're uploading an image called 'test.png', the URL will be this:

https://[Your-Bucket-Name].s3.[S3-Region].amazonaws.com/[test.png]

I tried dependency injection but AWS didn't like that so I've changed my code to this: (in this example I'm receiving a base64 string, turning it into a BYTE and then into a SYSTEM.IO.Stream)

This is the request I'm sending up:

{ "image":"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
    }

Controller:

    public async Task<ActionResult> Index(string image)
    {
        AmazonS3Uploader amazonS3 = new AmazonS3Uploader();

        // This bit creates a random string that will be used as part of the URL
        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        var stringChars = new char[8];
        var random = new Random();

        for (int i = 0; i < stringChars.Length; i++)
        {
            stringChars[i] = chars[random.Next(chars.Length)];
        }

        var finalString = new String(stringChars);

        // This bit adds the '.png' as its an image
        var keyName = finalString + ".png";

        // This uploads the file to S3, passing through the keyname (which is the end of the URL) and the image string
        amazonS3.UploadFile(keyName, image);

        // This is what the final URL of the object will be, so you can use this variable later or save it in your database
        var itemUrl = "https://[your-bucket-name].s3.[S3-Region].amazonaws.com/" + keyName;

        return Ok();
    }

AmazonS3Uploader.cs

    private string bucketName = "your-bucket-name";

    public async void UploadFile(string keyName, string image)
    {
        byte[] bytes = System.Convert.FromBase64String(image);

        Stream stream = new MemoryStream(bytes);

        var myAwsAccesskey = "*************";
        var myAwsSecret = "**************************";

        var client = new AmazonS3Client(myAwsAccesskey, myAwsSecret, Amazon.RegionEndpoint.[S3-Region]);

        try
        {
            PutObjectRequest putRequest = new PutObjectRequest
            {
                BucketName = bucketName,
                Key = keyName,
                ContentType = "image/png",
                InputStream = stream
            };

            PutObjectResponse response = await client.PutObjectAsync(putRequest);

        }
        catch (AmazonS3Exception amazonS3Exception)
        {
            if (amazonS3Exception.ErrorCode != null &&
                (amazonS3Exception.ErrorCode.Equals("InvalidAccessKeyId")
                ||
                amazonS3Exception.ErrorCode.Equals("InvalidSecurity")))
            {
                throw new Exception("Check the provided AWS Credentials.");
            }
            else
            {
                throw new Exception("Error occurred: " + amazonS3Exception.Message);
            }
        }
    }

The only problem with this is if the file upload to S3 Fails, you might still get the URL, and if you're saving it to your database - you'll save the URL to the database but the object wont exist in the S3 bucket, so it won't lead anywhere. If you implement dependency injection - this shouldn't be an issue (dependency injection not implemented in this example)

chumberjosh
  • 400
  • 5
  • 19
  • 1
    Dont forget to URL encode your string if it has special characters – DollarAkshay Feb 24 '21 at 10:06
  • 3
    I actually found that there was a "-" after "s3" (not a "."). So `...s3-[S3-Region]...` or `$"https://{bucketName}.s3-{RegionEndpoint.USWest2.SystemName}.amazonaws.com/{HttpUtility.UrlEncode(key)}"` – derekantrican Mar 04 '21 at 18:10