Azure Блок Blob: «Указанный список блоков недействителен» при фиксации ранее зафиксированных блоков - PullRequest
1 голос
/ 14 марта 2020

Используя Azure .Storage.Blob. NET SDK v12, я пытаюсь добавить блок блоб. Основываясь на различной документации, кажется, что способ сделать это - зафиксировать список ранее зафиксированных идентификаторов блоков вместе с новыми идентификаторами блоков. Я убедился, что идентификаторы блоков имеют одинаковую длину. Но когда я пытаюсь зафиксировать идентификатор блока, который уже был зафиксирован, я получаю ошибку «400: указанный список блоков недействителен».

Вот упрощенный код, иллюстрирующий проблему:

// Create a blob container and a new block blob
string connectionString = @"...";
BlobServiceClient serviceClient = new BlobServiceClient(connectionString);
string containerName = Guid.NewGuid().ToString();
BlobContainerClient containerClient = serviceClient.CreateBlobContainer(containerName);
BlockBlobClient blobClient = containerClient.GetBlockBlobClient("some-blob");

// Stage and commit a block containing some dummy data
byte[] dummyData = new byte[1024];
byte[] firstBlockID = Encoding.UTF8.GetBytes("0");
string firstIDBase64 = Convert.ToBase64String(firstBlockID); // "MA=="
var stageResponse = blobClient.StageBlock(firstIDBase64, new MemoryStream(dummyData));
var responseInfo = stageResponse.GetRawResponse(); // 201: Created
var contentResponse = blobClient.CommitBlockList(new[] { firstIDBase64 });
responseInfo = contentResponse.GetRawResponse(); // 201: Created

// Stage a second block
byte[] secondBlockID = Encoding.UTF8.GetBytes("1");
string secondIDBase64 = Convert.ToBase64String(secondBlockID); // "MQ=="
stageResponse = blobClient.StageBlock(secondIDBase64, new MemoryStream(dummyData));
responseInfo = stageResponse.GetRawResponse(); // 201: Created

// Sanity check: 
// Viewing the block list in the debugger shows both the committed block ID 
// "MA==" and uncommitted block ID "MQ==", as expected.
BlockList blockList = blobClient.GetBlockList(BlockListTypes.All).Value;

// Commit both the previously committed block. and the new uncommitted one.
// This results in the the error:
//    Status: 400(The specified block list is invalid.)
//    ErrorCode: InvalidBlockList
blobClient.CommitBlockList(new[] { firstIDBase64, secondIDBase64 });

1 Ответ

1 голос
/ 14 марта 2020

Отличный вопрос! Я считаю, что проблема заключается в том, как реализован метод CommitBlockList. Я проверил запрос / ответ в Fiddler, и это то, что отправляется в службу хранения:

<BlockList>
    <Uncommitted>MA==</Uncommitted>
    <Uncommitted>MQ==</Uncommitted>
</BlockList>

Если вы заметили, что хотя блок с MA== идентификатором блока был зафиксирован, SDK все еще отправляет его как Uncommitted и это вызывает проблему.

Затем я посмотрел документацию этого метода here, и это то, что я заметил для параметра base64BlockIds:

Укажите Uncommitted Идентификаторы закодированных в Base64 , чтобы указать, что служба BLOB-объектов должна искать только в списке незафиксированных блоков для именованных блоков. Если блок не найден в списке незафиксированных блоков, он не будет записан как часть большого двоичного объекта, и будет выдано исключение RequestFailedException.

Поскольку блок с MA== идентификатором блока уже существует зафиксировано, и вы отправляете его как незафиксированный блок, служба хранения выдает исключение.

ИМХО, реализация метода не соответствует операции Put Block List REST API. SDK следует изменить, чтобы учесть этот сценарий, учитывая, что это вполне возможно сделать с помощью REST API. Я бы порекомендовал открыть для этого вопрос на SDK Repository.

...