Azure Functions Triggers and Bindings - Part 2 - Blob storage
This is part 2 of the Azure Functions Triggers and Bindings series where Triggers and Bindings are explored with C# examples. In this post, Azure Blob storage is explored with In-Process and Isolated Functions.
Triggers and Bindings
There are 3 use cases that we can take advantage of when dealing with Azure Blob storage on Azure Functions:
- Listen to blobs with
BlobTrigger
, applied to both In-Process and Isolated models. - Read blobs from the storage with
Blob
andBlobInput
, an input binding applied to In-Process and Isolated models respectively. - Save blobs to the storage with
Blob
andBlobOutput
, an output binding applied to In-Process and Isolated models respectively.
Both triggers and bindings are explored below with In-Process and Isolated model examples.
They have similar implementations, except in Isolated mode, where bindings cannot handle Streams but only strings.
Triggers
A single trigger BlobTrigger
is available in both implementations.
In-Process Triggers
The In-Process model leverages the NuGet package Microsoft.Azure.WebJobs.Extensions.Storage
, version 5.0.1
(currently).
Trigger.cs
public class Trigger
{
[FunctionName(nameof(BlobTrigger))]
public void BlobTrigger([BlobTrigger("marketing/{name}")]Stream myBlob, string name, ILogger log)
{
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
}
}
Isolated Triggers
The Isolated model leverages the NuGet package Microsoft.Azure.Functions.Worker.Extensions.Storage
, version 5.0.1
(currently).
Trigger.cs
public class Trigger
{
private readonly ILogger _logger;
public Trigger(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Trigger>();
}
[Function(nameof(BlobTrigger))]
public void BlobTrigger([BlobTrigger("marketing/{name}", Connection = "AzureWebJobsStorage")] string myBlob, string name)
{
_logger.LogInformation($"C# Blob trigger function Processed blob\n Name:{name} \n Size: {myBlob.Length} Bytes");
}
}
Testing Triggers
To validate the triggers, either start the In-process or Isolated model, then add a file to the blob container marketing
by using Azure Storage Explorer.
- Create the blob container
marketing
- Click to upload a file
- Select
Upload Files
- Click to select a file
- Upload it
This should trigger the BlobTrigger
function.
Bindings
There are 2 types of bindings, the Input
used for reading blobs and the Output
used for writing blobs.
In all examples below, there are different blob name patterns1 to make a trigger match.
Input In-Process Binding
Input.cs
public class Input
{
[FunctionName(nameof(BlobInput))]
public void BlobInput(
[BlobTrigger("marketing-txt/{name}.txt")] Stream blobTrigger, string name,
[Blob("marketing-txt/{name}.txt", FileAccess.Read)] Stream blobContent, ILogger log)
{
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}.txt \n Size: {blobTrigger.Length} Bytes");
// READ stream just uploaded
using var reader = new StreamReader(blobContent);
var data = reader.ReadToEnd();
log.LogInformation($"{data}");
}
}
The implementation above gets triggered when a .txt
file is uploaded to marketing-txt
container, then with the Input
binding it reads [Blob("marketing-txt/{name}.txt", FileAccess.Read)] the Stream
just uploaded.
Input Isolated Binding
Input.cs
public class Input
{
private readonly ILogger _logger;
public Input(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Input>();
}
[Function(nameof(BlobInput))]
public void BlobInput(
[BlobTrigger("marketing-txt/{name}.txt", Connection = "AzureWebJobsStorage")] string blobTrigger, string name,
[BlobInput("marketing-txt/{name}.txt", Connection = "AzureWebJobsStorage")] string blobContent
)
{
_logger.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}.txt \n Size: {blobTrigger.Length} Bytes");
_logger.LogInformation($"{blobContent}");
}
}
The implementation above gets triggered when a .txt
file is uploaded to marketing-txt
container, then with the Input
binding it reads [BlobInput("marketing-txt/{name}.txt", Connection = "AzureWebJobsStorage")] the string
just uploaded.
Output In-Process Binding
Output.cs
public class Output
{
[FunctionName(nameof(BlobOutput))]
public void BlobOutput(
[BlobTrigger("marketing-txt/{name}.csv")] Stream blobTrigger, string name,
[Blob("marketing-csv/{name}.csv", FileAccess.Write)] Stream blobContent, ILogger log)
{
log.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}.csv \n Size: {blobTrigger.Length} Bytes");
// DELETE csv from marketing-txt container
var storageConnectionString = System.Environment.GetEnvironmentVariable("AzureWebJobsStorage");
BlobClient client = new BlobClient(storageConnectionString, "marketing-txt", $"{name}.csv");
client.DeleteIfExists();
}
}
The implementation above gets triggered when a .csv
file is uploaded erroneously to marketing-txt
container, then with the Output
binding it writes [Blob("marketing-csv/{name}.csv", FileAccess.Write)] the Stream
to another container marketing-csv
, and within the implementation, the .csv
file is deleted from marketing-txt
.
Output Isolated Binding
Output.cs
public class Output
{
private readonly ILogger _logger;
public Output(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Output>();
}
[Function(nameof(BlobOutput))]
[BlobOutput("marketing-csv/{name}.csv", Connection = "AzureWebJobsStorage")]
public string BlobOutput([BlobTrigger("marketing-txt/{name}.csv", Connection = "AzureWebJobsStorage")] string blobTrigger, string name)
{
_logger.LogInformation($"C# Blob trigger function Processed blob\n Name:{name}.csv \n Size: {blobTrigger.Length} Bytes");
// DELETE csv from marketing-txt container
var storageConnectionString = System.Environment.GetEnvironmentVariable("AzureWebJobsStorage");
BlobClient client = new BlobClient(storageConnectionString, "marketing-txt", $"{name}.csv");
client.DeleteIfExists();
return blobTrigger;
}
}
The implementation above gets triggered when a .csv
file is uploaded erroneously to marketing-txt
container, then with the Output
binding it writes [BlobOutput("marketing-csv/{name}.csv", Connection = "AzureWebJobsStorage")] the string
to another container marketing-csv
, and within the implementation, the .csv
file is deleted from marketing-txt
.
Testing Bindings
To validate the Input
binding, create the container marketing-txt
and then upload a .txt
file to it. In this case, the function will print out the body of the .txt
file uploaded.
Last, but not least, to validate the Output
binding, create the container marketing-csv
and then upload a .csv
file to the marketing-txt
container, as we are trying to check how the function is going to move files automatically.
The examples are available on PlayGoKids repository.
More posts will come to exemplify other Triggers and Bindings available in Azure Functions. Stay tuned.
- References: blob name patterns↩