2011-06-19 21 views
11

Internamente ASP.NET tiene un espacio de direcciones de 2 GB, pero en realidad solo tiene menos de 1 GB para cargar (consulte http://support.microsoft.com/?id=295626). Además IIS 7 tiene un límite de 30 MB (ver http://www.iislogs.com/steveschofield/iis7-post-40-adjusting-file-upload-size-in-iis7) y que supuestamente tienen que correrCómo cargar archivos grandes al blob de Azure desde una página web

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

en el servidor para ir más allá de este límite de 30 MB. Pero, ¿cómo puedo ejecutar esto en mis servidores de Azure?

Además, según http://support.microsoft.com/?id=295626

Durante el proceso de carga, ASP.NET cargas de todo el archivo en la memoria antes el usuario puede guardar el archivo en el disco .

, por lo que agotaré rápidamente el límite de memoria si muchos usuarios cargan archivos grandes a la vez. En mi código a continuación utilizo las transmisiones, pero supongo que todo el archivo se carga primero en la memoria. ¿Es este el caso?

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(); 
      } 
     } 
    } 
} 

Soy consciente de las herramientas de carga de las páginas web no como http://azureblobuploader.codeplex.com/, pero realmente lo necesita ser subido desde una página web.

Por lo tanto, mis preguntas son:

  1. Cómo puedo subir archivos a la burbuja que son más de 2 GB de una página web
  2. ¿Cómo puedo grandes archivos de carga de una página web como una corriente que no se come toda la memoria
  3. Si la solución es escribir mi propio HttpModule o HttpHandler para manejar mi carga, ¿cómo puedo instalar esto en mis servidores Azure? ¿Puedo usar HttpHandlers como http://neatupload.codeplex.com/ en Azure?
  4. Este proyecto no está en SharePoint, pero sé que en SharePoint tiene algo llamado proveedor Blob y que puede escribir el suyo, ¿hay proveedores Blob para ASP.NET?

También puedo mencionar que mi código anterior funciona bien de forma predeterminada con archivos de menos de 30 MB, uso SWFUpload V2.2.0 en el cliente.

Actualización 19 de junio 19:09: @YvesGoeleven en Twitter me dio una punta de la utilización de acceso compartido Firma (ver msdn.microsoft.com/en-us/library/ee395415.aspx) y subir el archivo directamente a Azure Blob Storage sin pasar por ASP.NET en absoluto. Creé un JSON WCF que devuelve un ut ut SAS válido para mi almacenamiento 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); 
     } 
    } 
} 

Funciona, pero no puede utilizarlo con SWFUpload ya que utiliza el verbo HTTP POST y no el verbo HTTP PUT que el Blob de almacenamiento Azure espera que cuando se crea un nuevo elemento de burbuja. ¿Alguien sabe cómo evitar esto sin tener mi propio componente cliente de Silverlight o Flash personalizado que utiliza el verbo HTTP PUT? Quería una barra de progreso al cargar los archivos, por lo tanto, un formulario enviado que utiliza PUT no es óptimo.

Para aquellos interesados ​​en el código de cliente (que no trabajará desde SWFUpload utiliza HTTP POST y PUT no como Azure Blob Storage espera):

<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> 

Actualización 19 de junio 21:07:

Pensé que, dado que SWFUpload es de código abierto, descargué la fuente y cambié el verbo de POST a PUT, lamentablemente Flash Player URLRequestMethod no admite otros verbos que GET y POST. Encontré una supuesta solución de problemas

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")); 

, pero esto solo funciona en Adobe Air y no con Flash Player.

He leído que SilverLight 3 y posterior es compatible con el verbo HTTP PUT, así que creo que tengo que escribir algunos códigos SilverLight para abrirme camino aquí. Encontré esta serie de artículos de blog que probablemente me ayuden aquí, http://blog.smarx.com/posts/uploading-windows-azure-blobs-from-silverlight-part-1-shared-access-signatures.

actualización @ 27. Junio ​​'11:

Ahora he arreglado para subir archivos grandes (probado con 4,5 GB de archivos) de una página web utilizando un cliente de Silverlight a medida que escribió basándose en la proyecto en http://blog.smarx.com/posts/uploading-windows-azure-blobs-from-silverlight-part-1-shared-access-signatures. Como Silverlight admite tanto el verbo HTTP PUT que requiere Azure Blob Storage como las cargas progresivas, ahora tengo la posibilidad de cargar archivos masivos directamente en Azure Blob Storage y no tengo que pasar por una solución ASP.NET, también obtener algunas barras de progreso agradables y el usuario puede cancelar en el medio de la carga si lo desea. El uso de la memoria en el servidor es mínimo, ya que no se carga todo el archivo antes de colocarlo en Azure Blob Storage. Uso una firma de acceso compartido (consulte msdn.microsoft.com/en-us/library/ee395415.aspx) que se proporciona desde un servicio WCF RESTfull a pedido. Creo que esta solución es la mejor que encontramos. Gracias.

actualización @ 18. Julio '11:

He creado un proyecto de código abierto, con lo que he encontrado aquí:

http://azureslfileuploader.codeplex.com/

Respuesta

3

hecho, me hizo exactamente lo mismo recientemente. Creé una aplicación de Silverlight Client para manejar cortar los datos y enviarlos a Azure.

This es un ejemplo de trabajo que he seguido que hace exactamente eso. Basta seguir esto y tu trabajo está casi hecho para ti.

3

independientemente del tipo de código que utilice. Si escribe un código del lado del servidor, el archivo irá a su webrole y luego se producirán varias molestias, como el papeleo de reciclaje y la reintentación de cargas fallidas. Eliminé estos problemas a través de un control Silverlight del lado del cliente, que no solo cargaba los archivos con tolerancia a errores sino que también lo hacía a gran velocidad. Puede descargar mi muestra y leer cómo la construí desde: Pick Your Azure File Upload Control: Silverlight and TPL or HTML5 and AJAX

Cuestiones relacionadas