Using (Table Storage) Bindings in Azure Functions
By rickvdbosch
- 3 minutes read - 544 wordsMy post Using Triggers & Bindings in Azure Functions V2 drew quite some attention over the past months. But there is a lot more to say about them. Time for a small follow up 😁
Covered previously ⌚
In my previous post we covered relative simple things like writing to blob storage and putting messages on a Service Bus. But the bindings for Azure Functions are so much more powerful.
Example: Table storage binding ✅
I really love Table storage, especially for simple data. Connecting to a storage account and getting the information from Table storage is not a lot of code, although it does feel like there’s a lot of plumbing there.
Let’s start with getting everything from a Table storage table (this is a very inefficient query, by the way).
var connectionString = "<YOUR-CONNECTION-STRING>";
var storageAccount = CloudStorageAccount.Parse(connectionString);
var tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("<TABLE-NAME>");
await table.CreateIfNotExistsAsync();
var result = await GetEntitiesFromTable(table);
Just to be complete, here’s the code for the GetEntitiesFromTable
method (we’ll be re-using this later on):
private static async Task<IEnumerable<T>> GetEntitiesFromTable<T>(CloudTable table) where T : ITableEntity, new()
{
TableQuerySegment<T> querySegment = null;
var entities = new List<T>();
var query = new TableQuery<T>();
do
{
querySegment = await table.ExecuteQuerySegmentedAsync(query, querySegment?.ContinuationToken);
entities.AddRange(querySegment.Results);
} while (querySegment.ContinuationToken != null);
return entities;
}
So the first block of code, all 6 lines of them, are needed to:
- Get the connection string of the storage to connect to
- Create an instance of CloudStorageAccount
- Create a client to connect to Table Storage
- Get an instance of CloudTable for a specific table
- Create the table if it doesn’t exist
- Get all the entities from the CloudTable
Simplify that 🔽
Let’s see if Bindings can help make this simpler:
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
[Table("<TABLE-NAME>", Connection = "connstring")] CloudTable table,
ILogger log)
{
var result = await GetEntitiesFromTable(table);
}
The Table binding on line 3 takes care of 5 of all 6 lines of code of our previous implementation. That means there’s only 1 line* of code left! We’re automatically getting an instance of CloudTable
pointing to the right table in the right storage account, just by specifying the binding the right way. This is AWESOME!
* I know we still have the GetEntitiesFromTable method, but that also didn’t count in the first example, so there 😁
We can of course also get an instance of CloudTable
that points to a specific partition in the storage table by providing the partition key in the binding:
[Table("<TABLE-NAME>", "<PARTITION-KEY>", Connection = "connstring")] CloudTable table
Simpler! ⏬
How about we can have the binding provide you with exactly one entity that satisfies the query you would like to perform? Well, you can. In the example below we’re using the rowKey
that is specified as part of the URL for the HttpTrigger as the value for the row key of the entity in partition “<PARTITION-KEY>
” we would like to retrieve.
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "entities/{rowKey}")] HttpRequest req,
[Table("<TABLE-NAME>", "<PARTITION-KEY>", "{rowKey}", Connection = "connstring")] MyEntity entity
This abstracts away everything about connecting to table storage and querying for a specific entity… and just provides that one entity you’re looking for as a parameter to your Function.
Got questions? Contact me!
Hope this helps.