如何從網頁將大文件上傳到 Azure Blob
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/這樣的非網頁上傳工具,但我真的需要從網頁上傳它。
所以,我的問題是:
- 如何從網頁將大於 2 GB 的文件上傳到 Blob
- 如何從網頁上傳大文件作為不佔用所有記憶體的流
- 如果解決方案是編寫我自己的 HttpModule 或 HttpHandler 來處理我的上傳,我怎樣才能在我的 Azure 伺服器上安裝它?我可以在 Azure 上使用像http://neatupload.codeplex.com/這樣的 HttpHandlers 嗎?
- 這個項目不在 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"));,但這僅適用於 Adobe 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 月:
我用我在這裡找到的東西創建了一個開源項目:
我最近確實做了同樣的事情。我創建了一個 Silverlight 客戶端應用程序來處理切分數據並將其發送到 Azure。
這是我遵循的一個工作範例,它正是這樣做的。幾乎遵循這個,你的工作幾乎已經為你完成了。
無論您使用什麼程式碼模式。如果您編寫伺服器端程式碼,則文件將進入您的 webrole,然後會出現角色回收和重試失敗上傳等問題。我通過客戶端 Silverlight 控制項刪除了這些問題,該控制項不僅可以進行容錯上傳,而且可以以極快的速度進行上傳。您可以下載我的範例並閱讀我如何建構它:選擇您的 Azure 文件上傳控制項:Silverlight 和 TPL 或 HTML5 和 AJAX