Как загружать огромные файлы в большой двоичный объект Azure с веб-страницы

Внутренне ASP.NET имеет адресное пространство 2 ГБ, но на самом деле у вас меньше 1 ГБ свободного места для загрузки (см. http: / /support.microsoft.com/?id=295626 ). Вдобавок IIS 7 имеет ограничение в 30 МБ (см. 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 МБ. Но как я могу запустить это на моих серверах Azure?

Кроме того, согласно http://support.microsoft.com/?id=295626

В процессе загрузки ASP.NET загружает весь файл в память перед пользователь может сохранить файл в disk.

, поэтому я быстро исчерпаю лимит памяти, если многие пользователи загружают большие файлы одновременно. В моем коде ниже я использую потоки, но я предполагаю, что в любом случае весь файл сначала загружается в память. Так ли это?

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 ГБ с веб-страницы
  2. Как загрузить большие файлы с веб-страницы в виде потока, который не занимает всю память
  3. Если решение должен написать собственный HttpModule или HttpHandler для обработки моей загрузки, как я могу установить это на моих серверах Azure? Могу ли я использовать HttpHandlers, такие как http://neatupload.codeplex.com/ в Azure?
  4. Этого проекта нет в SharePoint, но я знаю, что в SharePoint у вас есть что-то, называемое поставщиком BLOB-объектов, и что вы Можете написать свой собственный, существуют ли поставщики BLOB-объектов для ASP.NET?

Я также могу упомянуть, что приведенный выше код отлично работает по умолчанию с файлами размером менее 30 МБ, я использую SWFUpload V2.2.0 на клиенте.

Обновление 19. июня 19:09: @YvesGoeleven в Твиттере дал мне совет по использованию подписи общего доступа (см. Msdn.microsoft.com/en-us/library/ee395415.aspx) и загрузки файла непосредственно в хранилище BLOB-объектов Azure без использования ASP.NET. . Я создал JSON WCF, который возвращает действительный SAS ut в мое хранилище BLOB-объектов.

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, а не команду HTTP PUT, которую хранилище BLOB-объектов Azure ожидает при создании нового элемента BLOB-объектов. Кто-нибудь знает, как обойти это, не создавая собственный клиентский компонент Silverlight или Flash, который использует команду HTTP PUT? Мне нужен индикатор выполнения при загрузке файлов, поэтому отправленная форма, использующая PUT, не оптимальна.

Для тех, кто интересуется клиентским кодом (который не будет работать, поскольку SWFUpload использует HTTP POST, а не PUT, как ожидает хранилище BLOB-объектов Azure):

    
    

Application Demo (ASP.Net 2.0)

Обновление 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 г .:

Теперь мне удалось успешно загрузить большие файлы (проверено с файлами размером 4,5 ГБ) с веб-страницы с помощью специального клиента Silverlight, который я написал на основе проекта. в http://blog.smarx.com/posts/uploading-windows-azure-blobs-from-silverlight-part-1-shared-access-signatures . Поскольку Silverlight поддерживает как команду HTTP PUT, которую требует хранилище BLOB-объектов Azure, так и прогрессивную загрузку, теперь у меня есть возможность выгружать большие файлы непосредственно в хранилище BLOB-объектов Azure, и мне не нужно использовать решение ASP.NET, я также Получите несколько хороших индикаторов выполнения, и пользователь может отменить в середине загрузки, если он / она хочет. Использование памяти на сервере минимально, поскольку весь файл не выгружается до того, как он будет помещен в хранилище BLOB-объектов Azure. Я использую подпись общего доступа (см. Msdn.microsoft.com/en-us/library/ee395415.aspx), которая предоставляется службой WCF RESTfull по запросу. Я думаю, что это лучшее решение, которое мы нашли. Спасибо.

Обновление @ 18 июля '11:

Я создал проект с открытым исходным кодом, используя то, что я нашел здесь:

http://azureslfileuploader.codeplex.com/

11
задан 17 July 2011 в 23:18
поделиться