· 7 years ago · Jul 16, 2018, 07:04 PM
1using Microsoft.AspNetCore.Mvc;
2using System.Linq;
3using System;
4using System.IO;
5using System.IO.Compression;
6using System.Net.Mime;
7using System.Threading.Tasks;
8using Amazon;
9using Amazon.Runtime;
10using Amazon.S3;
11using Amazon.S3.Model;
12
13namespace DigitalClaimPro.UI.Controllers
14{
15 public class YourController : Controller
16 {
17 [HttpGet]
18 public async Task<IActionResult> DownloadPhotos()
19 {
20 // Load files from Amazon S3, create ZIP file as stream
21 string accessKey = "YOURACCESSKEY...";
22 string secretKey = "Your+5ecre7+key+.....";
23 string bucketName = "YourBucketName";
24 var amazonStorageService = new AmazonStorageService(accessKey, secretKey, bucketName);
25 var zipFileStream = await amazonStorageService.DownloadFilesAsZipAsync("Folder/SubFolder/");
26
27 // Point response to handle content type
28 ContentDisposition cd = new ContentDisposition
29 {
30 FileName = "MyArchive.zip",
31 Inline = false // false = prompt the user for downloading; true = browser to try to show the file inline (useful for showing some file types inline - TXT, images, etc.)
32 };
33 Response.Headers.Add("Content-Disposition", cd.ToString());
34 Response.Headers.Add("X-Content-Type-Options", "nosniff");
35
36 // Return ZIP file
37 return File(zipFileStream, "application/zip");
38 }
39 }
40
41 public class FileDetails
42 {
43 public string RelativePath { get; set; }
44
45 public long Length { get; set; }
46
47 public string PhysicalPath { get; set; }
48
49 public string Name { get; set; }
50
51 public DateTimeOffset LastModified { get; set; }
52 }
53
54 public class AmazonStorageService
55 {
56 private readonly AmazonS3Config _config;
57 private readonly string _accessKey;
58 private readonly string _secretKey;
59 private readonly string _rootBucketName;
60
61 public AmazonStorageService(string accessKey, string secretKey, string bucketName)
62 {
63 _accessKey = accessKey;
64 _secretKey = secretKey;
65 _rootBucketName = bucketName;
66
67 string regionName = "us-east-1";
68 RegionEndpoint regionEndpoint = RegionEndpoint.EnumerableAllRegions.FirstOrDefault(
69 endpoint =>
70 string.Equals(endpoint.SystemName, regionName, StringComparison.CurrentCultureIgnoreCase) ||
71 string.Equals(endpoint.DisplayName, regionName, StringComparison.CurrentCultureIgnoreCase));
72
73 _config = new AmazonS3Config
74 {
75 RegionEndpoint = regionEndpoint,
76 ResignRetries = true,
77 DisableLogging = true,
78 Timeout = TimeSpan.FromSeconds(60)
79 };
80 }
81
82 public async Task<Stream> DownloadFilesAsZipAsync(string relativePathToAmazonDirectory)
83 {
84 var files = await ListContentAsync(relativePathToAmazonDirectory);
85
86 var memoryStream = new MemoryStream();
87 using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
88 {
89 foreach (FileDetails file in files)
90 {
91 using (Stream stream = await GetFileStreamAsync(file.RelativePath))
92 {
93 stream.Seek(0, SeekOrigin.Begin);
94 ZipArchiveEntry zipEntry = zipArchive.CreateEntry(file.Name);
95 using (Stream zipEntryStream = zipEntry.Open())
96 {
97 stream.CopyTo(zipEntryStream);
98 }
99 }
100 }
101 }
102
103 memoryStream.Position = 0;
104 return memoryStream;
105 }
106
107 private async Task<Stream> GetFileStreamAsync(string relativePath)
108 {
109 try
110 {
111 using (var client = CreateAmazonS3Client())
112 {
113 var request = new GetObjectRequest
114 {
115 BucketName = _rootBucketName,
116 Key = CheckRelativePath(relativePath)
117 };
118
119 using (var getObjectResponse = await client.GetObjectAsync(request))
120 {
121 using (var responseStream = getObjectResponse.ResponseStream)
122 {
123 var stream = new MemoryStream();
124 await responseStream.CopyToAsync(stream);
125 return stream;
126 }
127 }
128 }
129 }
130 catch (Exception exception)
131 {
132 throw WrapException("Load operation failed.", exception);
133 }
134 }
135
136 private async Task<FileDetails[]> ListContentAsync(string relativeDirectoryPath)
137 {
138 try
139 {
140 using (AmazonS3Client client = CreateAmazonS3Client())
141 {
142 ListObjectsRequest request = new ListObjectsRequest
143 {
144 BucketName = _rootBucketName,
145 Prefix = CheckRelativePath(relativeDirectoryPath)
146 };
147
148 ListObjectsResponse response = await client.ListObjectsAsync(request);
149 FileDetails[] files = response.S3Objects
150 .Select(
151 s3Object =>
152 {
153 var relativeFilePath = s3Object.Key;
154 return new FileDetails
155 {
156 Name = Path.GetFileName(relativeFilePath),
157 PhysicalPath = BuildUrl(s3Object.Key),
158 RelativePath = relativeFilePath,
159 Length = s3Object.Size,
160 LastModified = s3Object.LastModified
161 };
162 })
163 .ToArray();
164 return files;
165 }
166 }
167 catch (Exception exception)
168 {
169 throw WrapException("List content operation failed.", exception);
170 }
171 }
172
173 private AmazonS3Client CreateAmazonS3Client()
174 {
175 var credentials = GetCredentials();
176 var client = new AmazonS3Client(credentials, _config);
177 return client;
178 }
179
180 private AWSCredentials GetCredentials()
181 {
182 if (!string.IsNullOrWhiteSpace(_accessKey) && !string.IsNullOrWhiteSpace(_secretKey))
183 {
184 return new BasicAWSCredentials(_accessKey, _secretKey);
185 }
186
187 throw new Exception("Amazon secret/access keys must be configured.");
188 }
189
190 private static Exception WrapException(string error, Exception exception)
191 {
192 var innerException = exception is AggregateException ae
193 ? ae.Flatten().InnerException
194 : exception;
195 return new Exception(error, innerException);
196 }
197
198 private static string CheckRelativePath(string relativePath)
199 {
200 // Replace left slash to right one if needed
201 relativePath = relativePath ?? "";
202 if (relativePath.Contains(@""))
203 {
204 relativePath = relativePath.Replace(@"", "/");
205 }
206
207 return relativePath;
208 }
209
210 private string BuildUrl(string key)
211 {
212 return $"https://{_rootBucketName}.s3.amazonaws.com/{key}";
213 }
214 }
215}