11

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/

4

4 回答 4

3

无论您使用什么代码模式。如果您编写服务器端代码,则文件将进入您的 webrole,然后会出现角色回收和重试失败上传等问题。我通过客户端 Silverlight 控件删除了这些问题,该控件不仅可以进行容错上传,而且可以以极快的速度进行上传。您可以下载我的示例并阅读我如何构建它:选择您的 Azure 文件上传控件:Silverlight 和 TPL 或 HTML5 和 AJAX

于 2011-11-01T18:30:12.947 回答
3

我最近确实做了同样的事情。我创建了一个 Silverlight 客户端应用程序来处理切分数据并将其发送到 Azure。

是我遵循的一个工作示例,它正是这样做的。几乎遵循这个,你的工作几乎已经为你完成了。

于 2011-06-27T21:37:29.007 回答
2

我们可以使用并行上传将非常大的文件上传到 Azure 存储。这意味着我们需要将大文件分成小文件包,然后上传这些包。上传完成后,我们可以将数据包加入原始数据包。有关完整代码,请参阅以下链接 http://tuvian.wordpress.com/2011/06/28/how-to-upload-large-size-fileblob-to-azure-storage-using-asp-netc/

于 2011-06-28T13:54:40.947 回答
-1

对于这部分问题:

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

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

您可以使用启动任务执行此操作 - 请参阅http://richardprodger.wordpress.com/2011/03/22/azure-iis7-configuration-with-appcmd/

于 2011-06-20T11:02:20.987 回答