使用Amazon S3 API - ASP.MVC上的SDK直接下载文件的更好方法

时间:2017-01-05 20:40:24

标签: asp.net-mvc amazon-web-services amazon-s3

亚马逊提供了大量的文档,但是我丢失了很多文档,所以这是我目前的上传/下载文件服务。上传按预期工作,但在下载时我必须将文件下载到物理路径,然后将下载提供给用户,我没有多少使用流的经验。这是连接到Amazon API的FileManagerService类。

using Amazon.S3;
using Amazon.S3.Model;
public class FileManagerService
    {
        public FileManagerService()
        {
            string serverPath = HttpContext.Current.Server.MapPath("~/");
            string uploadPath = Path.Combine(serverPath, "FileUploads");
            Directory.CreateDirectory(uploadPath);
            UploadDirectory = uploadPath;
        }
        private string UploadDirectory { get; set; }

        private docucloudEntities db = new docucloudEntities();

        private IAmazonS3 S3Client = new AmazonS3Client();

        private string S3Bucket = "bucketname";

        public async Task<string> DownloadFile(string AmazonFileKey, string FileName)
        {
            var fileRequest = new GetObjectRequest
            {
                BucketName = S3Bucket,
                Key = AmazonFileKey
            };

            var localRoute = Path.Combine(UploadDirectory, FileName);

            using (var fileObject = await S3Client.GetObjectAsync(fileRequest))
            {
                if (fileObject.HttpStatusCode == HttpStatusCode.OK)
                {
                    fileObject.WriteResponseStreamToFile(localRoute);
                }
            }
            return localRoute;
        }
    }

此方法返回字符串,但它还没有完成try catch块,但它目前有效。这是我的控制器方法,将文件下载到客户端:

public class FileManagerController : Controller
{
    private FileManagerService FileService = new FileManagerService();

    public async Task<ActionResult> DownloadFileAmazon(long FileId)
    {
        if (db.Archivos.Any(i => i.ArchivoID == FileId))
        {
            var archivo = db.Archivos.Single(i => i.ArchivoID == FileId);
            var rutaarchivo = await FileService.DownloadFile(archivo.Ruta, archivo.Nombre);
            if (System.IO.File.Exists(rutaarchivo))
            {
                var fileBytes = System.IO.File.ReadAllBytes(rutaarchivo);
                var response = new FileContentResult(fileBytes, "application/octet-stream");
                response.FileDownloadName = archivo.Nombre;
                System.IO.File.Delete(rutaarchivo);
                return response;
            }else
            {
                return HttpNotFound();
            }
        }else
        {
            return HttpNotFound();
        }
    }
}

所以在控制器上我读取文件字节并在删除文件后提供下载,但这可能导致性能降低,有一种实现直接下载的方法。

1 个答案:

答案 0 :(得分:0)

据我所知,即使文档这样说,也没有理由处理GetObjectResponseGetObjectAsync的返回类型)。 GetObjectResponse未实施IDisposable,但正在继承StreamResponse。但是,据我所知it's only disposing the ResponseStream。因此,您可以将GetObjectResponsefileObject.ResponseStream)的流与标题(ContentType)中的fileObject.Headers.ContentType一起返回,然后您可以将其作为控制器中的文件返回:< / p>

[HttpGet]
[Route("blob/{filename}")]
public async Task<IActionResult> GetFile(string filename)
{
    try
    {
        var file = await _fileStorageService.GetBlobAsync(filename);

        return File(file.Stream, file.ContentType);
    }
    catch (Exception ex)
    {
        // Handle exceptions
    }
}

FileResult将在写入文件后处理该流,以便流最终得到处理。