Azure Functions - Blob Storage Trigger

stack of shipping containers

Today's modern applications are interacting with a larger variety of data stores than they have ever had to in the past. This is not to say that interacting with file storage is anything new, however, the options for storing files are ever-increasing. One of these storage options is Azure Storage. This service has many options, including the ability to quickly host a static site, but we are here to talk about blob storage and responding to changes to a container with an Azure Function.

In this series, we have seen enough Azure Function implementations that we should be seeing the pattern. Let's take a look at the implementation first, then enumerate the differences.

public class BlobStorageFunction
{
    [FunctionName("BlobAudit")]
    public void Run(
        [BlobTrigger("sample/{name}")]Stream blobStream,
        string name,
        ILogger log)
    {
        log.LogInformation($"File uploaded to 'sample' container with filename: {name}");
    }
}

After a quick review of the implementation, 2 lines are different than the other implementations. The first of which is expected. That is the first argument to the function. In this case, the first argument is decorated with a BlobTrigger annotation. The constructor of which accepts a string argument. This string defines the container the trigger is to be listening to, or another way to phrase it, the path to the blob. Something of interest in this string is the curly brackets around the second path section. If you are familiar with Web API, this will seem all too familiar. This is a value passed from the caller, we will detail this more later. Lastly, the type of the first argument is a stream. This is the stream of the blob. If you were so interested in inspecting the contents of the blob within this function, you could do just that.

The second string argument is a new one for the example Azure Function implementations. As mentioned above, the BlobTrigger constructor accepts a string, of which our string contains {name}. Seeing the similarity in name of this second argument? Well, here it is! This {name} argument is the name of the blob that has recently been touched. Say your implementation was looking for any *.json file to process. This would be the way to identify those file types.

One thing you should be questioning at this time is, where does the configuration live for this trigger? As we saw with the Azure Service Bus consumer, there is a need to define the connection to the other Azure resource that the Azure Function is to react to. There is an option to set the Connection property on the BlobTrigger annotation. But, in the case of this example, I opted to use a local Azure Storage Emulator. Which can be configured as a local.settings.json file. for reference, here are the contents of the file:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
    }
}

As for differences, those are it. Such a subtle difference, with such a big impact. One final thought on this topic, what are some sample use-cases of such a trigger? I have been thinking the same and this is what came to my mind:

  • Audit logging
  • File sanitizing
  • Triggering subsequent file processing (data import processing)
  • Re-formatting/post-processing of file content
    • Generate thumbnail images
    • Convert file to different type (JPG -> PNG -> SVG)