我想使用 C# 在 Azure 容器中上传 blob。我在 UI(角度)中将 blob 分解为块,对于每个块,我调用我的 c# API。 这对于小文件来说效果很好。但对于大文件(甚至 130 MB),文件未完全上传,API 会抛出错误“指定的阻止列表无效。”
[HttpPost("{fileName}")]
public async Task<IActionResult> UploadChunk(string fileName, List<IFormFile> chunk)
{
if (chunk.Count == 0)
{
return BadRequest("No file received from the request");
}
if (chunk.Count > 1)
{
return BadRequest("The request contains more than one file. Only one file can be uploaded at a time");
}
var blockBlobClient = blobContainerClient.GetBlockBlobClient(fileName);
if (!await blockBlobClient.ExistsAsync())
{
await blockBlobClient.UploadAsync(new MemoryStream());
}
byte[] buffer = new byte[chunk[0].Length];
await chunk[0].OpenReadStream().ReadAsync(buffer, 0, buffer.Length);
var blockId = Guid.NewGuid().ToString();
var blockIdBytes = Encoding.UTF8.GetBytes(blockId);
var base64BlockId = Convert.ToBase64String(blockIdBytes);
await blockBlobClient.StageBlockAsync(base64BlockId, new MemoryStream(buffer));
var blockList = await blockBlobClient.GetBlockListAsync(BlockListTypes.All);
var totalBlockCount = blockList.Value.CommittedBlocks.Count() + blockList.Value.UncommittedBlocks.Count(); // This line just returned 14 blocks
await blockBlobClient.CommitBlockListAsync(blockList.Value.UncommittedBlocks.Select(block => block. Name).ToList());
}
我已将以下代码添加到 Program.cs 中,并将超过 130 MB 的文件块上传到 Azure Blob 存储。
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = 500 * 1024 * 1024;
options.Limits.MaxRequestBufferSize = 500 * 1024 * 1024;
});
builder.Services.Configure<FormOptions>(options =>
{
options.ValueLengthLimit = 500 * 1024 * 1024;
options.MultipartBodyLengthLimit = 500 * 1024 * 1024;
});
程序.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.Configure<KestrelServerOptions>(options =>
{
options.Limits.MaxRequestBodySize = 500 * 1024 * 1024;
options.Limits.MaxRequestBufferSize = 500 * 1024 * 1024;
});
builder.Services.Configure<FormOptions>(options =>
{
options.ValueLengthLimit = 500 * 1024 * 1024;
options.MultipartBodyLengthLimit = 500 * 1024 * 1024;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
BlobController.cs:
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Specialized;
using Azure.Storage.Blobs.Models;
[ApiController]
[Route("api/[controller]")]
public class BlobController : ControllerBase
{
private readonly BlobServiceClient blobServiceClient;
private readonly string containerName = "<container_name>";
public BlobController()
{
var connectionString = "<connec_string>";
blobServiceClient = new BlobServiceClient(connectionString);
}
[HttpPost("{fileName}")]
public async Task<IActionResult> UploadChunk(string fileName, List<IFormFile> chunks)
{
try
{
if (chunks.Count == 0)
{
return BadRequest("No file received from the request");
}
if (chunks.Count > 1)
{
return BadRequest("The request contains more than one file can be uploaded at a time");
}
var blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName);
var blockBlobClient = blobContainerClient.GetBlockBlobClient(fileName);
if (!await blockBlobClient.ExistsAsync())
{
await blockBlobClient.UploadAsync(new MemoryStream());
}
var chunk = chunks[0];
var blockId = Guid.NewGuid().ToString();
var blockIdBytes = Encoding.UTF8.GetBytes(blockId);
var base64BlockId = Convert.ToBase64String(blockIdBytes);
byte[] buffer = new byte[chunk.Length];
await chunk.OpenReadStream().ReadAsync(buffer, 0, buffer.Length);
await blockBlobClient.StageBlockAsync(base64BlockId, new MemoryStream(buffer));
var blockList = await blockBlobClient.GetBlockListAsync(BlockListTypes.All);
var uncommittedBlocks = blockList.Value.UncommittedBlocks.ToList();
uncommittedBlocks.Sort((b1, b2) => string.CompareOrdinal(b1.Name, b2.Name));
await blockBlobClient.CommitBlockListAsync(uncommittedBlocks.Select(block => block.Name).ToList());
return Ok();
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex.Message}");
}
}
}
输出:
进程成功运行如下:
我将文件块上传到 Azure Blob 存储,如下所示。
注意: 确保您有稳定的互联网连接。
Azure 门户:
我将 130 MB 及更大的文件上传到 Azure Blob 存储,如下所示。