azure-webjobs-sdk-extensions
azure-webjobs-sdk-extensions copied to clipboard
Blob binding with ICloudBlob automatically sets BlobType to BlockBlob
A blob binding where ICloudBlob is used, the binding's BlobType is automatically set as BlockBlob.
This prevents the use case where the BlobType isn't known at compile time and you just want a catch all for all types.
If the blob is actually anything else besides a BlockBlob, it fails to interact with any method in the framework, unless you explicitly use CloudAppendBlob or CloudPagedBlob as type instead of ICloudBlob.
Repro steps
I'm currently using the IBinder since in my case, because I also don't know the actual path yet until later in the code, but I left that part out for clarity.
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
IBinder binder)
{
var path = "some-container/some-path.ext";
var blob = await binder.BindAsync<ICloudBlob>(new BlobAttribute(path, FileAccess.ReadWrite));
var contents = await blob.DownloadToByteArrayAsync(); // Fails if BlobType is anything else besides BlockType
}
Expected behavior
In the above example, DownloadToByteArrayAsync() should work, regardless of the actual blob type in the storage.
It might be solvable by having the BlobType property set to Unspecified instead of BlockBlob, based on my workaround. However, I do not know the inner workings of the bindings, and sadly I can't test it due to the property only having a getter.
Actual behavior
The current code throws the exception Blob type of the blob reference doesn't match blob type of the blob..
Known workarounds
By using the binding to get the preconfigured connection settings, and then re-getting the blob through the container, you get a CloudBlob that has its BlobType set to Unspecified. This allows the call FetchAttributesAsync() to get the actual blob type in order to re-get a blob reference with correct type.
Sadly GetBlobReference() returns a CloudBlob which doesn't implement ICloudBlob so in order to get one that does implement it (CloudAppendBlob, CloudBlockBlob, CloudPagedBlob) additional code is necessary.
var blobFromBinding = await binder.BindAsync<ICloudBlob>(new BlobAttribute(path, FileAccess.ReadWrite));
var blobFromContainer = blobFromBinding.Container.GetBlobReference(blobFromBinding.Name);
await blobFromContainer.FetchAttributesAsync();
var blobWithCorrectType = blobFromContainer.BlobType switch
{
BlobType.AppendBlob => blobFromBinding.Container.GetAppendBlobReference(blobFromBinding.Name),
BlobType.PagedBlob => blobFromBinding.Container.GetPagedBlobReference(blobFromBinding.Name),
_ => blobFromBinding.Container.GetBlockBlobReference(blobFromBinding.Name)
};
Related information
At time of writing, I'm using the latest storage package, which is v4.0.2.
Hi @b10-dslappendel ,Apologies for the delayed response, Can we know if you were able to find a solution here. Are you still facing this error
@v-anvari Other than using the workaround I've already given (or by using the v12 storage library directly and forgoing the blob bindings entirely), I haven't found a proper solution using the function bindings. And I can confirm that version 4.0.4 is still having this issue.
You might have created blob in different way and reading it by taking its reference in different way. Try write the code in below way for creating and updating the file both
public async Task<CloudAppendBlob> UpdateCSVinBlob(Stream fileStream, string containerName, string blobFullPath)
{
// Get the blob container
var containerClient = this.GetContainer(containerName);
if (containerClient != null)
{
CloudAppendBlob appBlob = containerClient.GetAppendBlobReference(blobFullPath);
if (!appBlob.Exists())
{
appBlob.CreateOrReplace();
}
appBlob.AppendFromStream(fileStream);
return appBlob;
}
return null;
}
No I haven't. Also, my issue has to do with the Azure functions blob binding.
As I'll be removing my work account in favor of my main account, I can contacted at @Archomeda from now on for further updates.