Не могу загрузить файл ~ 200 МБ в хранилище BLOB-объектов Azure на стороне главного сервера asp.net - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть серверная часть на ядре Asp.net, которая получает файл в Content-Type: заголовок формата multipart / form-data и отправляет его в хранилище Azure BLOB-объектов в потоке. Но когда я отправляю файл размером около 200 МБ и больше, у меня появляется ошибка

«Тело запроса слишком велико и превышает максимально допустимый предел»

, когда я искал, это могло произойти в старой версии WindowsAzure.Storage, но у меня есть версия 9.1.1. И как я посмотрел глубже, метод UploadFromStreamAsync по умолчанию использует чанк блоба на 4 МБ. Поэтому я не знаю, к чему только обратиться за помощью. Мой контроллер:

public async Task<IActionResult> Post(string folder)
    {
        string azureBlobConnectionString = _configuration.GetConnectionString("BlobConnection");
        // Retrieve storage account from connection string.
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(azureBlobConnectionString);

        HttpResponseUploadClass responseUploadClass = await Request.StreamFile(folder, storageAccount);
        FormValueProvider formModel = responseUploadClass.FormValueProvider;

        var viewModel = new MyViewModel();

        var bindingSuccessful = await TryUpdateModelAsync(viewModel, prefix: "",
            valueProvider: formModel);

        if (!bindingSuccessful)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
        }

        return Ok(responseUploadClass.Url);
    }

И класс, куда я отправляю поток файлового потока в лазурный блоб

 public static async Task<HttpResponseUploadClass> StreamFile(this HttpRequest request, string folder, CloudStorageAccount blobAccount)
    {
        CloudBlobClient blobClient = blobAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference(folder);
        CloudBlockBlob blockBlob = null;

        if (!MultipartRequestHelper.IsMultipartContentType(request.ContentType))
        {
            throw new Exception($"Expected a multipart request, but got {request.ContentType}");
        }
        var formAccumulator = new KeyValueAccumulator();

        var boundary = MultipartRequestHelper.GetBoundary(
            MediaTypeHeaderValue.Parse(request.ContentType),
            DefaultFormOptions.MultipartBoundaryLengthLimit);
        var reader = new MultipartReader(boundary, request.Body);

        var section = await reader.ReadNextSectionAsync();
        while (section != null)
        {
            ContentDispositionHeaderValue contentDisposition;
            var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
            var disposition = ContentDispositionHeaderValue.Parse(section.ContentDisposition);
            if (hasContentDispositionHeader)
            {
                if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
                {
                    try
                    {
                        string fileName = HttpUtility.UrlEncode(disposition.FileName.Value.Replace("\"", ""), Encoding.UTF8);
                        blockBlob = container.GetBlockBlobReference(Guid.NewGuid().ToString());
                        blockBlob.Properties.ContentType = GetMimeTypeByWindowsRegistry(fileName);
                        blockBlob.Properties.ContentDisposition = "attachment; filename*=UTF-8''" + fileName;
                        await blockBlob.UploadFromStreamAsync(section.Body);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }
                }
                else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
                {
                    var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name);
                    var encoding = GetEncoding(section);
                    using (var streamReader = new StreamReader(
                        section.Body,
                        encoding,
                        detectEncodingFromByteOrderMarks: true,
                        bufferSize: 1024,
                        leaveOpen: true))
                    {
                        var value = await streamReader.ReadToEndAsync();
                        if (String.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
                        {
                            value = String.Empty;
                        }
                        formAccumulator.Append(key.Value, value);

                        if (formAccumulator.ValueCount > DefaultFormOptions.ValueCountLimit)
                        {
                            throw new InvalidDataException($"Form key count limit {DefaultFormOptions.ValueCountLimit} exceeded.");
                        }
                    }
                }
            }
            section = await reader.ReadNextSectionAsync();
        }
        var formValueProvider = new FormValueProvider(
            BindingSource.Form,
            new FormCollection(formAccumulator.GetResults()),
            CultureInfo.CurrentCulture);

        return new HttpResponseUploadClass{FormValueProvider = formValueProvider, Url = blockBlob?.Uri.ToString()};
    }

1 Ответ

0 голосов
/ 27 апреля 2018

Как вы уже сказали, каждый блочный блоб может иметь различный размер, не более 100 МБ (4 МБ для запросов с использованием версий REST до 2016-05-31) и блочный блоб может включать до 50 000 блоков.

Если вы пишете блочный блоб размером не более 256 МБ (64 МБ для запросов с использованием версий REST до 2016-05-31), вы можете загрузить его в в целом с помощью одной операции записи , см. Put Blob .

Клиенты хранилища по умолчанию имеют максимальную загрузку 32 МБ для одного блока , устанавливаемую с помощью свойства SingleBlobUploadThresholdInBytes. Если загрузка BLOB-объектов превышает значение, указанное в этом свойстве, клиенты хранилища разбивают файл на блоки. Вы можете установить количество потоков, используемых для параллельной загрузки блоков, используя свойство ParallelOperationThreadCount.

BlobRequestOptions requestoptions = new BlobRequestOptions()
{
    SingleBlobUploadThresholdInBytes = 1024 * 1024 * 50, //50MB
    ParallelOperationThreadCount = 12,
};

CloudStorageAccount account = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudBlobClient blobclient = account.CreateCloudBlobClient();
blobclient.DefaultRequestOptions = requestoptions;
CloudBlobContainer blobcontainer = blobclient.GetContainerReference("uploadfiles");
blobcontainer.CreateIfNotExists();
CloudBlockBlob blockblob = blobcontainer.GetBlockBlobReference("bigfiles");

Для более подробной информации, вы можете обратиться к этой теме .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...