I’ve been doing a lot of work recently with Azure Functions in which I use Table Storage as the backend for it. This led me to start using the FSharp.Azure.Storage NuGet package which gives a nicer API for Table Storage (and also happens to be written by a former colleague of mine).
But there’s a catch, FSharp.Azure.Storage
is designed to work with the CloudTableClient
which you would normally get like so:
1
2
3
4
5
6
7
| open Microsoft.WindowsAzure.Storage
open Microsoft.WindowsAzure.Storage.Table
let account = CloudStorageAccount.Parse "UseDevelopmentStorage=true;" //Or your connection string here
let tableClient = account.CreateCloudTableClient()
let inGameTable game = inTable tableClient "Games" game
|
But when we’re using an Azure Function we’re likely doing a binding in our Function parameter, like this:
1
2
3
4
| [<FunctionName("Some_Function")>]
let someFunction ([<HttpTrigger(AuthorizationLevel.Function, "get", Route = "some-function")>] req: HttpRequest)
([<Table("MyData")>] dataTable: CloudTable) =
// do stuff
|
Notice that here we’ll receive a CloudTable
, which has already been created from the CloudTableClient
. This is because Azure Functions takes care of the creation and “connection pooling” (for lack of a better description) so that we don’t need to do it ourselves as the Functions scale. We also need the name of the table that we’re working with, again we don’t need to worry about that in our Function, since we already have the CloudTable
.
Thankfully, we can go from a CloudTable
back to the CloudTableClient
and get the name of the table at the same time. To do this I’ve created some new functions in my F# codebase:
1
2
3
4
5
6
7
8
9
10
11
12
| module azureTableUtils
open FSharp.Azure.Storage.Table
open Microsoft.WindowsAzure.Storage.Table
let fromTableToClientAsync (table: CloudTable) q = fromTableAsync table.ServiceClient table.Name q
let fromTableToClient (table: CloudTable) q = fromTable table.ServiceClient table.Name q
let inTableToClientAsync (table: CloudTable) o = inTableAsync table.ServiceClient table.Name o
let inTableToClient (table: CloudTable) o = inTable table.ServiceClient table.Name o
let inTableToClientAsBatch (table: CloudTable) o = inTableAsBatch table.ServiceClient table.Name o
let inTableToClientAsBatchAsync (table: CloudTable) o = inTableAsBatchAsync table.ServiceClient table.Name o
|
From the CloudTable
you can access the ServiceClient
to get the CloudTableClient
and Name
gives you the name!
Now we can use it in our Azure Function like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| [<FunctionName("Some_Function")>]
let someFunction ([<HttpTrigger(AuthorizationLevel.Function, "get", Route = "some-function")>] req: HttpRequest)
([<Table("MyData")>] dataTable: CloudTable) =
async {
let! data = Query.all<MyData>
|> fromTableToClientAsync dataTable
let! data
|> Seq.map (fun (d, _) ->
{ d with Value = "Updated" })
|> Replace
|> autobatch
|> List.map (inTableToClientBatch dataTable)
|> Async.Parallel
return OkResult() :> IActionResult
} |> Async.StartAsTask
|
Feel free to use those functions in your own applications. You will have to explcitly type the table
argument as CloudTable
as the F# type inference isn’t able to pick up that that’s what it is otherwise.
Happy F#‘ing!