LargeBlobs - Jusas/AzureTableDataStore GitHub Wiki

What is a LargeBlob?

The LargeBlob class defines a linked Azure Storage Blob inside a table entity. This allows you to store data that does not fit into the table row as a blob in Azure Blob Storage. This could be an image, a document or whatever data you want to store. It also allows you to easily retrieve the data after you have fetched the table row.

LargeBlob properties

LargeBlob has 4 properties:

  • Filename: the name of the file, e.g. myimage.jpg
  • ContentType: the MIME content type of the file, e.g. image/jpeg
  • Length: the byte length of the data
  • AsyncDataStream: the lazy getter to the data stream

Creating/storing a LargeBlob

So let's take a look how we'd store a large blob content along with table entity data:

var myEntity = new MyEntity()
{
    PartitionKey = "pkey",
    RowKey = "rkey",
    MyBlob = new LargeBlob("myimage.jpeg", new FileStream("files/myimage.jpg", FileMode.Open, FileAccess.Read), "image/jpeg"),
    MySecondBlob = (LargeBlob) null
};

var store = new TableDataStore<MyEntity>(...);
await store.InsertAsync(BatchingMode.None, myEntity);

The InsertAsync() call will first attempt to insert the table row into the table and if it succeeds it is followed with the blob upload operation. The blob gets uploaded to the designated blob storage to the path that is built up from the entity property path and the filename, i.e. if our table name was myentities and our container name was tableblobs the path to the blob would be https://<mystorage>.blob.core.windows.net/tableblobs/myentities/pkey/rkey/MyBlob/myimage.jpeg.

Due to these two operations being two individual operations what may happen is that the blob upload fails for some reason, in which case you'd end up with a table entity that basically has a broken reference to the blob that doesn't exist. This will of course become apparent when an exception is thrown and it is then up to you how you want to handle that situation. See Exceptions and exception handling for more information.

Updating LargeBlobs

Note that the previous example the second LargeBlob MySecondBlob was null; in the case of insert this simply does not upload any blob. However if this was a Merge (aka Update) operation then the interpretation of null depends on the LargeBlobNullBehavior parameter: if the Merge operation is executed with LargeBlobNullBehavior.IgnoreProperty then the null value simply means to ignore the property, i.e. nothing will be done an existing blob. If however the operation is executed with LargeBlobNullBehavior.DeleteBlob then the null means that the blob should be deleted, and any existing blob will get deleted from Blob Storage.

So, in this example we update the entity and delete the blob from the storage by setting it to null:

var myUpdatedEntity = new MyEntity()
{
    PartitionKey = "pkey",
    RowKey = "rkey",
    MyBlob = null,
    MySecondBlob = (LargeBlob) null
};

var store = new TableDataStore<MyEntity>(...);
await store.MergeAsync(BatchingMode.None, selectMergedPropertiesExpression: null, 
    largeBlobNullBehavior:LargeBlobNullBehavior.DeleteBlob, myUpdatedEntity);

Or if we just want to replace one blob with a new one:

var myUpdatedEntity = new MyEntity()
{
    PartitionKey = "pkey",
    RowKey = "rkey",
    MyBlob = new LargeBlob("mynewfile.jpg", new FileStream(...), "image/jpeg")
};

myUpdatedEntity.MyBlob = new LargeBlob("mynewfile.jpg", new FileStream(...), "image/jpeg");
await store.MergeAsync(BatchingMode.None, entity => new { entity.MyBlob },
    largeBlobNullBehavior:LargeBlobNullBehavior.IgnoreProperty, myUpdatedEntity);

Getting LargeBlob data

Once you have saved an entity with a LargeBlob you can get access to its outlying HTTP Stream quite easily:

var myEntity = await store.GetAsync(x => x.PartitionKey == "pkey" && x.RowKey == "rkey");

using (var imageStream = await myEntity.MyBlob.AsyncDataStream.Value)
{
    using (var reader = new BinaryReader(imageStream))
    {
        var dataBytes = reader.ReadBytes((int)myEntity.MyBlob.Length);
        // do stuff with downloaded data
    }
}

The Value getter returns the Stream directly from Azure Blob Storage for your consumption.

Batch operations

Since the Azure Table Storage and Azure Blob Storage operations are two separate operations they can't be tied together very tightly. Therefore when you do batched operations, LargeBlobs generally can't be touched. See the Explanation of batching modes. However if you still do want to use batched operations accompanied with blob operations you can use the BatchingMode.Loose mode. This mode allows you to perform the table operations in batches but the blob operations will still need to be performed separately at the side. This may be faster but may lead to broken entities that you will need to deal with if some blob operations fail.

⚠️ **GitHub.com Fallback** ⚠️