【问题标题】:Duplicating File Uploading Process - Asp.net WebApi复制文件上传过程 - Asp.net WebApi
【发布时间】:2019-06-27 14:19:55
【问题描述】:

我创建了一个 Web API,允许用户发送文件并上传到 Azure 存储。它的工作方式是,客户端应用程序将连接到 API 以将一个或多个文件发送到文件上传控制器,而控制器将负责诸如

  • 将文件上传到 Azure 存储
  • 更新数据库

效果很好,但我认为这不是正确的方法,因为现在我可以看到有两个不同的过程

  1. 将文件从客户端的文件系统上传到我的 Web API(服务器)
  2. 从 API(服务器)上传文件到 Azure 存储

这让我觉得我正在复制上传过程,因为同一个文件首先从客户端(文件系统)传输到 API(服务器),然后是 Azure(目标)。我觉得需要向客户端显示两个进度条以获取文件上传进度(从客户端到服务器,然后从服务器到 Azure)——这对我来说没有意义,我觉得我的方法不正确。

我的 API 最多接受 250MB,因此您可以想象过载。

你们觉得呢?

//// API 控制器

if (!Request.Content.IsMimeMultipartContent("form-data"))
   {
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
   }

var provider = new RestrictiveMultipartMemoryStreamProvider();
var contents = await Request.Content.ReadAsMultipartAsync(provider);
int Total_Files = contents.Contents.Count();
foreach (HttpContent ctnt in contents.Contents) 
 {
   await storageManager.AddBlob(ctnt)
 }

////// 流

#region SteamHelper

public class RestrictiveMultipartMemoryStreamProvider : MultipartMemoryStreamProvider
{
    public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
    {
        var extensions = new[] { "pdf", "doc", "docx", "cab", "zip" };
        var filename = headers.ContentDisposition.FileName.Replace("\"", string.Empty);
        if (filename.IndexOf('.') < 0)
            return Stream.Null;

        var extension = filename.Split('.').Last();
        return extensions.Any(i => i.Equals(extension, StringComparison.InvariantCultureIgnoreCase))
                   ? base.GetStream(parent, headers)
                   : Stream.Null;
    }
}

#endregion SteamHelper

///// AddBlob

public async Task<string> AddBlob(HttpContent _Payload)
        {
            CloudStorageAccount cloudStorageAccount = KeyVault.AzureStorage.GetConnectionString();
            CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
            CloudBlobContainer cloudBlobContainer = cloudBlobClient.GetContainerReference("SomeContainer");
            cloudBlobContainer.CreateIfNotExists();
            try
            {
                byte[] fileContentBytes = _Payload.ReadAsByteArrayAsync().Result;
                CloudBlockBlob blob = cloudBlobContainer.GetBlockBlobReference("SomeBlob");
                blob.Properties.ContentType = _Payload.Headers.ContentType.MediaType;
                blob.UploadFromByteArray(fileContentBytes, 0, fileContentBytes.Length);
                var B = await blob.CreateSnapshotAsync();
                B.FetchAttributes();
                return "Snapshot ETAG: " + B.Properties.ETag.Replace("\"", "");
            }
            catch (Exception X)
            {
                return ($"Error : " + X.Message);
            }            
        }

【问题讨论】:

  • 使用流怎么样?
  • 嗨,我用代码更新了问题,是的,我正在使用 Stream

标签: azure asp.net-web-api azure-storage


【解决方案1】:

这让我觉得我正在复制上传过程 同一个文件首先传送到 API(服务器),然后传送到 Azure (目标)来自客户端(文件系统)。

我认为你是对的。一种可能的解决方案是让您的 API 生成 Shared Access Signature (SAS) token 并在客户端希望上传文件时将该 SAS 令牌/URI 返回给客户端。

使用此 SAS URI,您的客户端可以直接将文件上传到 Azure 存储,而无需先将其发送到您的 API。客户端上传文件成功后,可以向API发送消息更新数据库。

您可以在此处阅读有关 SAS 的更多信息:https://docs.microsoft.com/en-us/azure/storage/common/storage-dotnet-shared-access-signature-part-1

很久以前我还写过一篇关于使用 SAS 的博文,您可能会觉得它很有用:https://gauravmantri.com/2013/02/13/revisiting-windows-azure-shared-access-signature/

【讨论】:

  • 我考虑过共享访问,但我真的希望所有客户端都先通过我的 API 并让 API 完成该过程,也许有一种方法可以在从客户?所以上传收到的任何'bytes []'并继续上传直到完成
  • 你也可以这样做,但我认为你会浪费你的服务器资源恕我直言。你有什么理由想要这样做吗?
  • API 将成为公共 API(所有开发人员都可以访问)以与其他应用程序集成。
猜你喜欢
  • 1970-01-01
  • 2013-11-10
  • 2012-11-14
  • 2014-07-04
  • 1970-01-01
  • 2020-03-27
  • 2012-05-07
  • 1970-01-01
  • 2013-06-23
相关资源
最近更新 更多