Asp.net

如何從網頁將大文件上傳到 Azure Blob

  • November 1, 2011

ASP.NET 內部有 2 GB 的定址空間,但實際上您只有不到 1 GB 的可用上傳空間(請參閱http://support.microsoft.com/?id=295626)。此外 IIS 7 的上限為 30 MB(請參閱http://www.iislogs.com/steveschofield/iis7-post-40-adjusting-file-upload-size-in-iis7),您應該執行

appcmd set config "My Site/MyApp" -section:requestFiltering -requestLimits.maxAllowedContentLength:104857600 -commitpath:apphost

在伺服器上超出此 30 MB 限制。但是如何在我的 Azure 伺服器上執行它呢?

另外,根據http://support.microsoft.com/?id=295626

在上傳過程中,ASP.NET 將整個文件載入到記憶體中,然後使用者才能將文件保存到磁碟。

,所以如果很多使用者一次上傳大文件,我會很快耗盡記憶體限制。在下面的程式碼中,我使用了流,但我猜想整個文件還是先上傳到記憶體中。是這樣嗎?

using System;
using System.Web.Security;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace WebPages
{
   public partial class Upload : System.Web.UI.Page
   {
       CloudBlobClient BlobClient = null;
       CloudBlobContainer BlobContainer = null;

       void InitBlob()
       {
           // Setup the connection to Windows Azure Storage
           var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
           BlobClient = storageAccount.CreateCloudBlobClient();

           // Get and create the container
           BlobContainer = BlobClient.GetContainerReference("publicfiles");
       }

       protected void Page_Load(object sender, EventArgs e)
       {
           //if (Membership.GetUser() == null) return;   // Only allow registered users to upload files

           InitBlob();

           try
           {
               var file = Request.Files["Filedata"];

               var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
               BlobClient = storageAccount.CreateCloudBlobClient();

               // Make a unique blob name
               var extension = System.IO.Path.GetExtension(file.FileName);

               // Create the Blob and upload the file
               var blobAddressUri = String.Format("{0}{1}", Guid.NewGuid(), extension);
               var blob = BlobContainer.GetBlobReference(blobAddressUri);

               blob.UploadFromStream(file.InputStream);

               // Set the metadata into the blob
               blob.Metadata["FileName"] = file.FileName;
               //blob.Metadata["Submitter"] = Membership.GetUser().UserName;
               blob.Metadata["Type"] = "Video";
               blob.Metadata["Description"] = "Test";
               blob.SetMetadata();

               // Set the properties
               blob.Properties.ContentType = file.ContentType;
               blob.SetProperties();
           }
           catch(Exception ex)
           {
               System.Diagnostics.Trace.TraceError("Upload file exception: {0}", ex.ToString());
               // If any kind of error occurs return a 500 Internal Server error
               Response.StatusCode = 500;
               Response.Write("An error occured while uploading the file");
               Response.End();
           }
       }
   }
}

我知道像http://azureblobuploader.codeplex.com/這樣的非網頁上傳工具,但我真的需要從網頁上傳它。

所以,我的問題是:

  1. 如何從網頁將大於 2 GB 的文件上傳到 Blob
  2. 如何從網頁上傳大文件作為不佔用所有記憶體的流
  3. 如果解決方案是編寫我自己的 HttpModule 或 HttpHandler 來處理我的上傳,我怎樣才能在我的 Azure 伺服器上安裝它?我可以在 Azure 上使用像http://neatupload.codeplex.com/這樣的 HttpHandlers 嗎?
  4. 這個項目不在 SharePoint 上,但我知道在 SharePoint 中有一個叫做 Blob 提供程序的東西,而且你可以自己編寫,是否有用於 ASP.NET 的 Blob 提供程序?

我還可以提一下,我上面的程式碼預設情況下適用於小於 30 MB 的文件,我在客戶端上使用 SWFUpload V2.2.0。

更新 19. 六月 19:09: Twitter 上的 @YvesGoeleven 給了我一個使用共享訪問簽名的提示(請參閱 msdn.microsoft.com/en-us/library/ee395415.aspx )並將文件直接上傳到 Azure Blob 儲存,無需完全通過 ASP.NET。我創建了一個 JSON WCF,它向我的 blob 儲存返回一個有效的 SAS ut。

using System.ServiceModel;
using System.ServiceModel.Web;

namespace WebPages.Interfaces
{
   [ServiceContract]
   public interface IUpload
   {
       [OperationContract]
       [WebInvoke(Method = "GET",
           ResponseFormat = WebMessageFormat.Json)]
       string GetUploadUrl();
   }
}

--------

using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.ServiceModel.Activation;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace WebPages.Interfaces
{
   [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   public class UploadService : IUpload
   {
       CloudBlobClient BlobClient;
       CloudBlobContainer BlobContainer;

       public UploadService()
       {
           // Setup the connection to Windows Azure Storage
           var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
           BlobClient = storageAccount.CreateCloudBlobClient();

           // Get and create the container
           BlobContainer = BlobClient.GetContainerReference("publicfiles");
       }

       string JsonSerialize(string url)
       {
           var serializer = new DataContractJsonSerializer(url.GetType());
           var memoryStream = new MemoryStream();

           serializer.WriteObject(memoryStream, url);

           return Encoding.Default.GetString(memoryStream.ToArray());
       }

       public string GetUploadUrl()
       {
           var sasWithIdentifier = BlobContainer.GetSharedAccessSignature(new SharedAccessPolicy()
           {
               Permissions = SharedAccessPermissions.Write,
               SharedAccessExpiryTime =
                   DateTime.UtcNow.AddMinutes(60)
           });
           return JsonSerialize(BlobContainer.Uri.AbsoluteUri + "/" + Guid.NewGuid() + sasWithIdentifier);
       }
   }
}

它可以工作,但我不能將它與 SWFUpload 一起使用,因為它使用 HTTP POST 動詞,而不是 Azure Blob 儲存在創建新 blob 項時期望的 HTTP PUT 動詞。任何人都知道如何在不製作我自己的使用 HTTP PUT 動詞的自定義 Silverlight 或 Flash 客戶端組件的情況下解決這個問題?上傳文件時我想要一個進度條,因此使用 PUT 的送出表單不是最佳的。

對於那些對客戶端程式碼感興趣的人(由於 SWFUpload 使用 HTTP POST 而不是像 Azure Blob Storage 所期望的那樣 PUT ,因此無法正常工作):

   <div id="header">
       <h1 id="logo"><a href="/">SWFUpload</a></h1>
       <div id="version">v2.2.0</div>
   </div>
   <div id="content">
       <h2>Application Demo (ASP.Net 2.0)</h2>
       <div id="swfu_container" style="margin: 0px 10px;">
           <div>
               <span id="spanButtonPlaceholder"></span>
           </div>
           <div id="divFileProgressContainer" style="height: 75px;"></div>
           <div id="thumbnails"></div>
       </div>
   </div>

<script type="text/javascript" language="javascript">
       $(document).ready(function () {

           $.ajax({
               url: '/Interfaces/UploadService.svc/GetUploadUrl',
               success: function (result) {
                   var parsedResult = $.parseJSON(result);
                   InitUploadFile(parsedResult);
               }
           });


           function InitUploadFile(uploadUrl) {
               //alert(uploadUrl);
               var swfu = new SWFUpload({
                   // Backend Settings
                   upload_url: uploadUrl,
                   post_params: {
                       "ASPSESSID": "<%=Session.SessionID %>"
                   },

                   // File Upload Settings
                   file_size_limit: "100 MB",
                   file_types: "*.*",
                   file_types_description: "All file types",
                   file_upload_limit: "0",    // Zero means unlimited

                   // Event Handler Settings - these functions as defined in Handlers.js
                   //  The handlers are not part of SWFUpload but are part of my website and control how
                   //  my website reacts to the SWFUpload events.
                   file_queue_error_handler: fileQueueError,
                   file_dialog_complete_handler: fileDialogComplete,
                   upload_progress_handler: uploadProgress,
                   upload_error_handler: uploadError,
                   upload_success_handler: uploadSuccess,
                   upload_complete_handler: uploadComplete,

                   // Button settings
                   button_image_url: "Images/swfupload/XPButtonNoText_160x22.png",
                   button_placeholder_id: "spanButtonPlaceholder",
                   button_width: 160,
                   button_height: 22,
                   button_text: '<span class="button">Select files <span class="buttonSmall">(2 MB Max)</span></span>',
                   button_text_style: '.button { font-family: Helvetica, Arial, sans-serif; font-size: 14pt; } .buttonSmall { font-size: 10pt; }',
                   button_text_top_padding: 1,
                   button_text_left_padding: 5,

                   // Flash Settings
                   flash_url: "Js/swfupload-2.2.0/swfupload.swf", // Relative to this file

                   custom_settings: {
                       upload_target: "divFileProgressContainer"
                   },

                   // Debug Settings
                   debug: false
               });
           }
      });
   </script>

更新 19. 六月 21:07:

我認為由於 SWFUpload 是開源的,因此我下載原始碼並將動詞從 POST 更改為 PUT,遺憾的是 Flash Player URLRequestMethod 不支持除 GET 和 POST 之外的其他動詞。我確實找到了一個所謂的解決方法

private function BuildRequest():URLRequest {
  // Create the request object
  var request:URLRequest = new URLRequest();
  request.method = URLRequestMethod.POST;
  request.requestHeaders.push(new URLRequestHeader("X-HTTP-Method-Override", "PUT"));

,但這僅適用於 Adob​​e Air,不適用於 Flash Player。

我已經讀過 SilverLight 3 和更高版本支持 HTTP PUT 動詞,所以我認為我必須編寫一些 SilverLight 程式碼才能到達這裡。我確實在http://blog.smarx.com/posts/uploading-windows-azure-blobs-from-silverlight-part-1-shared-access-signatures找到了這個可能對我有幫助的部落格文章系列。

更新@ 27. 2011 年 6 月:

我現在已經成功地使用我根據http://blog.smarx.com/posts/uploading-windows中的項目編寫的自定義 Silverlight 客戶端從網頁上傳大文件(使用 4,5 Gb 文件測試)azure-blob-from-silverlight-part-1-shared-access-signatures. 由於 Silverlight 支持 Azure Blob 儲存所需的 HTTP PUT 動詞並支持漸進式上傳,因此我現在可以將大量文件直接上傳到 Azure Blob 儲存,而且我不必通過 ASP.NET 解決方案,我也獲得一些不錯的進度條,如果他/她願意,使用者可以在上傳過程中取消。伺服器上的記憶體使用量很少,因為在將整個文件放入 Azure Blob 儲存之前不會上傳整個文件。我使用 WCF RESTfull 服務應要求提供的共享訪問簽名(請參閱 msdn.microsoft.com/en-us/library/ee395415.aspx)。我認為這個解決方案是我們找到的最好的解決方案。謝謝。

更新@ 18. 2011 年 7 月:

我用我在這裡找到的東西創建了一個開源項目:

http://azureslfileuploader.codeplex.com/

我最近確實做了同樣的事情。我創建了一個 Silverlight 客戶端應用程序來處理切分數據並將其發送到 Azure。

是我遵循的一個工作範例,它正是這樣做的。幾乎遵循這個,你的工作幾乎已經為你完成了。

無論您使用什麼程式碼模式。如果您編寫伺服器端程式碼,則文件將進入您的 webrole,然後會出現角色回收和重試失敗上傳等問題。我通過客戶端 Silverlight 控制項刪除了這些問題,該控制項不僅可以進行容錯上傳,而且可以以極快的速度進行上傳。您可以下載我的範例並閱讀我如何建構它:選擇您的 Azure 文件上傳控制項:Silverlight 和 TPL 或 HTML5 和 AJAX

引用自:https://stackoverflow.com/questions/6402253