How to dynamically set blob name in an Azure Function
How to dynamically set blob name in an Azure Function

How to dynamically set blob name in an Azure Function

2020, Jul 29    

Hi All! Today we’re going to see how to dynamically set the blob name and write to it in an Azure Function. This is probably my first Azure article ever, and probably the first one of a long list 🙂

I’ll probably end up writing something about Azure and Event Sourcing at some point, so if you’re interested don’t forget to take a look at my other articles.

So, let’s suppose we have a nice Azure Function with a BlobTrigger, meaning that the function will be triggered every time a file is uploaded to a specific Blob Container.

[FunctionName("MyFancyFunction")]
public static async Task Run([BlobTrigger("inbound/{name}", Connection = "AzureWebJobsStorage")] Stream inboundBlob, string name)
{
    // do something here
}

As you can see, we have access to an input stream and we also get the filename. The AzureWebJobsStorage configuration variable will store the connection string to the Blob Container.

Now, how can we _write **_to a stream instead?

One simple option is to add a Stream parameter decorated with the [Blob] attribute:

public static async Task Run([BlobTrigger("inbound/{name}", Connection = "AzureWebJobsStorage")] Stream inboundBlob,
[Blob("outbound/{name}", Connection = "AzureWebJobsStorage", Access = FileAccess.Write)] Stream outboundBlob, 
string name){
    // do something here
}

The two streams will share the name, although the destination Container in this case is different. We can use several patterns for the Blob path, for a detailed explanation check here.

Using the {name} pattern, our Function will be called with any filename, even with extensionless files. In case we want a bit more control, we can use this format instead: {blobName}.{blobExtension} .

[FunctionName("InboundBlobEncode")]
public static async Task Run([BlobTrigger("inbound/{blobName}.{blobExtension}", Connection = "AzureWebJobsStorage")]Stream inboundBlob,
string blobName, 
string blobExtension){
    // function body here
}

We can leverage this pattern for example if we want our Function to execute only for specific extensions (eg {blobName}.jpg ).

In some cases, however, we might want to generate the output filename at runtime. We could leverage the** {rand-guid}** expression or even {Datetime}, but in that case, we won’t have real control over it. We can’t even store it in a temporary variable for later reuse.

This is the situation where imperative binding comes to the rescue: by adding an instance of _IBinder _as input parameter, we can generate the name of the destination Blob with our own rules and directly get a reference to it:

public static async Task Run(/*other input params*/, IBinder binder){
    var outBlobId = Guid.NewGuid();
    var outboundBlob = new BlobAttribute($"outbound/{outBlobId}", FileAccess.Write);
    using var writer = binder.Bind<Stream>(outboundBlob);
    // process the stream
}

In this snippet, we’re creating a new GUID and using it as Blob name. We can, later on, use it to create a message and send it to a Queue to be picked up by another process.

Did you like this post? Then