Based on this Microsoft example, this so answer and this blog post I can get declarative bindings to compile. At runtime, I get a System.NullReferenceException: Object reference not set to an instance of an object
from the binder.
I've tried moving the Binder to constructor. I've tried both Binder
and IBinder
and dug through a ton of docs. Can someone point me in the right direction?
Function
public class BeaconIngestion
{
private readonly ILogger<BeaconIngestion> _logger;
public BeaconIngestion(ILogger<BeaconIngestion> logger )
{
_logger = logger;
}
[Function(nameof(BeaconIngestion))]
[StorageAccount("DATA_STORAGE_ACCOUNT_CONNECTION_STRING")]
public async Task Run([EventHubTrigger("messages/events", Connection = "IOTHUB_CONNECTION_STRING") ] EventData[] events,
Binder binder)
{
foreach (EventData _event in events) //leading underscore because 'event is a keyword.
{
string message = System.Text.Encoding.UTF8.GetString(_event.Body.ToArray());
_logger.LogInformation("Event Body: {body}", message);
_logger.LogInformation("Event Content-Type: {contentType}", _event.ContentType);
string path = $"landing/{DateTime.UtcNow.ToString("yyyy/MM/dd/HH_mm_ss")}data.json";
_logger.LogInformation("Sending data to {path} using binder {binder}", path, binder);
using (var writer = await binder.BindAsync<TextWriter>(new BlobAttribute(path, FileAccess.Write)))
{
writer.Write("Hello World");
}
}
}
}
host.json
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
},
"enableLiveMetricsFilters": true
}
},
"extensions": {
"blobs": {
"maxDegreeOfParallelism": 4,
"poisonBlobThreshold": 2
}
}
}
local.settins.json
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
"IOTHUB_CONNECTION_STRING": "<connectionstring>",
"DATA_STORAGE_ACCOUNT_CONNECTION_STRING" : "<connectionstring>"
}
}
Program.cs
using Microsoft.Extensions.Hosting;
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.Build();
host.Run();
AFAIK, IBinder and Binder can't be used in isolated function as they are the attributes of Microsoft.Azure.WebJobs
and also confirmed by product team in this github issue.
Alternatively, I have used the below code to write the data into Blob storage using BlobContainerClient attribute.
Code:
using System;
using Azure.Messaging.EventHubs;
using Azure.Storage.Blobs;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace FunctionApp33
{
public class Function1
{
private readonly ILogger<Function1> _logger;
public Function1(ILogger<Function1> logger)
{
_logger = logger;
}
[Function(nameof(Function1))]
public async Task Run([EventHubTrigger("samples-workitems", Connection = "EventHub_ConnectionString")] EventData[] events,
BlobContainerClient blobContainerClient)
{
foreach (EventData @event in events)
{
_logger.LogInformation("Event Body: {body}", @event.Body);
_logger.LogInformation("Event Content-Type: {contentType}", @event.ContentType);
var blobServiceClient = new BlobServiceClient("Storage account connection string");
//Create a unique name for the container
string containerName = "demo";
// Create the container and return a container client object
blobContainerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
// Create a local file in the ./data/ directory for uploading and downloading
string localPath = "data";
Directory.CreateDirectory(localPath);
string fileName = "test.txt";
string localFilePath = Path.Combine(localPath, fileName);
// Write text to the file
await File.WriteAllTextAsync(localFilePath, "Hello, World!");
// Get a reference to a blob
BlobClient blobClient = blobContainerClient.GetBlobClient(fileName);
Console.WriteLine("Uploading to Blob storage as blob:\n\t {0}\n", blobClient.Uri);
// Upload data from the local file
await blobClient.UploadAsync(localFilePath, true);
}
}
}
}
Output:
References: Quickstart: Azure Blob Storage library - .NET | Microsoft Learn.