Comment télécharger d'énormes fichiers vers le blob Azure à partir d'une page web

interne ASP.NET dispose d'un espace d'adressage de 2 Go, mais en réalité vous n'avez que moins de 1 Go libre pour les téléchargements (voir http://support.microsoft.com/?id=295626 ). En outre, IIS 7 a un plafond de 30 MB ( voir ). http://www.iislogs.com/steveschofield/iis7-post-40-adjusting-file-upload-size-in-iis7 ) et vous auriez à courir

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

sur le serveur pour aller au-delà de cette limite de 30 Mo. Mais comment puis-je exécuter cette sur mes serveurs Azure?

aussi, selon http://support.microsoft.com/?id=295626

pendant le processus de téléchargement, ASP.NET charge tout le fichier en mémoire avant l'utilisateur peut sauvegarder le fichier disque.

, donc je vais rapidement épuiser la limite de mémoire si de nombreux utilisateurs téléchargent de gros fichiers à la fois. Dans mon code ci-dessous, j'utilise les flux, mais je devine que l'ensemble le fichier est d'abord téléchargé en mémoire. Est-ce le cas?

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

je suis au courant d'outils non de téléchargement de page web comme http://azureblobuploader.codeplex.com / , mais j'ai vraiment besoin qu'il soit téléchargé à partir d'une page web.

donc, mes questions sont:

  1. Comment puis-je télécharger des fichiers sur le blob qui sont plus de 2 GO à partir d'une page web
  2. Comment puis-je télécharger de grands fichiers à partir une page web comme un flux qui ne mange pas toute la mémoire
  3. si la solution est d'écrire mon propre HttpModule ou HttpHandler pour gérer mon téléchargement, Comment puis-je l'installer sur mes serveurs Azure? Puis-je utiliser des HttpHandlers comme http://neatupload.codeplex.com / on Azure?
  4. ce projet n'est pas sur SharePoint, mais je sais que dans SharePoint vous avez quelque chose appelé un fournisseur Blob et que vous pouvez écrire votre propre, sont-il Blob Fournisseurs de ASP.NET je ne sais pas.

je peux également mentionner que mon code ci-dessus fonctionne très bien par défaut avec des fichiers inférieurs à 30 Mo, J'utilise SWFUpload V2.2.0 sur le client.

mise à jour 19. 19 Juin: 09: @YvesGoeleven sur Twitter m'a donné un conseil d'utiliser la Signature D'accès partagé (voir msdn.microsoft.com/en-us/library/ee395415.aspx ) et le téléchargement du fichier directement dans le stockage Blob Azure sans passer par le ASP.NET pas du tout. J'ai créé un JSON WCF qui retourne un sasut valide à mon stockage 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);
        }
    }
}

cela fonctionne, mais je ne peux pas l'utiliser avec SWFUpload car il utilise le verbe HTTP POST et non le verbe HTTP PUT que le stockage Blob Azure attend lors de la création d'un nouvel élément blob. Quelqu'un sait comment contourner cela sans faire mon propre Silverlight personnalisé ou composant client Flash qui utilise le verbe HTTP PUT? Je voulais une barre de progression lors du téléchargement des fichiers, donc un formulaire soumis qui les usages mis ne sont pas optimaux.

pour ceux qui sont intéressés par le code client (qui ne fonctionnera pas puisque SWFUpload utilise HTTP POST et non pas mis comme Azure Blob Storage attend):

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

mise à jour 19. 21 juin: 07:

j'ai pensé depuis SWFUpload est open source que je télécharge la source et changer le Verbe de la poste à mettre, malheureusement le lecteur Flash URLRequestMethod ne supporte pas d'autres verbes que GET et POST. J'ai trouvé une supposée de travail autour de

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

, mais cela ne fonctionne Qu'avec Adobe Air et pas avec Flash Player.

J'ai lu que SilverLight 3 et plus tard supporte le verbe HTTP PUT, donc je pense que je dois écrire un code SilverLight pour obtenir mon chemin ici. J'ai bien trouvé cette série d'articles de blog qui va probablement m'aider ici http://blog.smarx.com/posts/uploading-windows-azure-blobs-from-silverlight-part-1-shared-access-signatures .

mise à Jour @ 27. Juin 11:

j'ai maintenant réussi à télécharger de grands fichiers (testés avec des fichiers de 4,5 Go) à partir d'une page Web en utilisant un client Silverlight personnalisé que j'ai écrit basé sur le projet dans http://blog.smarx.com/posts/uploading-windows-azure-blobs-from-silverlight-part-1-shared-access-signatures . Depuis Silverlight prend en charge à la fois le verbe mis HTTP que Azure Blob Storage nécessite et prend en charge les téléchargements progressifs, j'ai maintenant la possibilité de télécharger des fichiers massifs directement dans le stockage Blob Azure et je n'ai pas à aller ASP.NET solution, j'obtiens aussi de belles barres de progression et l'utilisateur peut annuler au milieu du téléchargement s'il/elle le souhaite. L'utilisation de la mémoire sur le serveur est minime puisque le fichier n'est pas téléchargé, avant d'être placé dans l'Azure Blob Storage. J'utilise une Signature D'accès partagé (voir msdn.microsoft.com/en-us/library/ee395415.aspx ) qui est fourni à partir d'un service RESTfull WCF sur demande. Je pense que cette solution est la meilleure que nous ayons trouvé. Grâce.

mise à Jour @ 18. Juillet '11:

j'ai créé un projet open source avec ce que j'ai trouvé ici:

http://azureslfileuploader.codeplex.com /

11
demandé sur Gabe 2011-06-19 16:07:47

4 réponses

j'ai fait exactement la même chose récemment. J'ai créé une application client Silverlight pour gérer les données et les envoyer à Azure.

ce est un exemple de travail que j'ai suivi qui fait exactement cela. Suivez - moi et votre travail est presque terminé.

3
répondu Gabe 2011-06-27 21:37:29

peu importe le code que vous utilisez. Si vous écrivez un code côté serveur, alors le fichier va aller à votre webrole et puis plusieurs douleurs telles que le recyclage de rôle et le retour des téléchargements défectueux va venir. J'ai retiré ces problèmes par un contrôle Silverlight côté client, qui non seulement a fait des chargements tolérant les défauts, mais aussi l'a fait à une grande vitesse. Vous pouvez télécharger mon échantillon et lire comment je l'ai construit à partir de: choisissez votre contrôle de téléchargement de fichier Azure: Silverlight et TPL ou HTML5 et AJAX

3
répondu Rahul 2011-11-01 18:30:12

nous pouvons télécharger de très gros fichiers dans le stockage azure en utilisant le téléchargement parallèle. Cela signifie que nous devons diviser les gros fichiers en morceaux de petits paquets de fichiers et et uoploaded ces paquets. Une fois le téléchargement terminé, nous pouvons rejoindre les paquets de un exemplaire original. Pour le code complet, reportez-vous au lien suivant http://tuvian.wordpress.com/2011/06/28/how-to-upload-large-size-fileblob-to-azure-storage-using-asp-netc/

2
répondu tuvian 2011-06-28 13:54:40

pour cette partie de la question:

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

sur le serveur pour aller au-delà de cette limite de 30 Mo. Mais comment puis-je lancer ceci sur mes serveurs Azure?

vous pouvez faire cela en utilisant les tâches de démarrage - voir http://richardprodger.wordpress.com/2011/03/22/azure-iis7-configuration-with-appcmd /

-1
répondu Stuart 2011-06-20 11:02:20