Reputation: 4288
I have an Azure Function and I want to have it taking message from the EventHub (This is fairly straightforward and works) and then put that information into Table Storage using Table binding at runtime.
Here's what I have so far:
public static async Task Run(string eventHubMessage, TraceWriter log, Binder binder)
{
var m = JsonConvert.DeserializeObject<Measurement>(eventHubMessage);
var attributes = new Attribute[]
{
new StorageAccountAttribute("AzureWebJobsTest"),
new TableAttribute(tableName, m.PartitionKey, m.RowKey)
};
using(var output = await binder.BindAsync<MyTableEntity>(attributes))
{
if(output == null)
log.Info($"4. output is null");
else
{
output.Minimum = m.Minimum;
output.Maximum = m.Maximum;
output.Average = m.Average;
output.Timestamp = m.Timestamp;
output.ETag = m.ETag;
output.WriteEntity(/* Need an operationContext*/)
}
}
}
public class MyTableEntity : TableEntity, IDisposable
{
public double Average { get; set;}
public double Minimum { get; set;}
public double Maximum { get; set;}
bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
}
disposed = true;
}
}
My problems;
1) The output is always null.
2) Even if output isn't null, I don't know what I need for an OperationContext or if calling ITableEntity.Write() is even correct way to get it to write to the table storage.
ETA Json Binding:
{
"bindings": [
{
"type": "eventHubTrigger",
"name": "eventHubMessage",
"direction": "in",
"path": "measurements",
"connection": "MeasurementsConnectionString"
}
],
"disabled": false
}
Upvotes: 6
Views: 8509
Reputation: 3711
If you want to use DynamicTableEntity because at compiletime you don't know what data will be contained in the message and you realize that table binding does not work for DynamicTableEntities anymore you can use the following method:
private static async Task ProcessMessage(string message, DateTime enqueuedTime)
{
var deviceData = JsonConvert.DeserializeObject<JObject>(message);
var dynamicTableEntity = new DynamicTableEntity();
dynamicTableEntity.RowKey = enqueuedTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
foreach (KeyValuePair<string, JToken> keyValuePair in deviceData)
{
if (keyValuePair.Key.Equals("MyPartitionKey"))
{
dynamicTableEntity.PartitionKey = keyValuePair.Value.ToString();
}
else if (keyValuePair.Key.Equals("Timestamp")) // if you are using a parameter "Timestamp" it has to be stored in a column named differently because the column "Timestamp" will automatically be filled when adding a line to table storage
{
dynamicTableEntity.Properties.Add("MyTimestamp", EntityProperty.CreateEntityPropertyFromObject(keyValuePair.Value));
}
else
{
dynamicTableEntity.Properties.Add(keyValuePair.Key, EntityProperty.CreateEntityPropertyFromObject(keyValuePair.Value));
}
}
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("myStorageConnectionString");
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
CloudTable table = tableClient.GetTableReference("myTableName");
table.CreateIfNotExists();
var tableOperation = TableOperation.Insert(dynamicTableEntity);
await table.ExecuteAsync(tableOperation);
}
Upvotes: 0
Reputation: 35154
To add a new entry to Table you should bind to IAsyncCollector
instead of entity itself, then create a new entity and call AddAsync
. The following snippet works for me:
var attributes = new Attribute[]
{
new StorageAccountAttribute("..."),
new TableAttribute("...")
};
var output = await binder.BindAsync<IAsyncCollector<MyTableEntity>>(attributes);
await output.AddAsync(new MyTableEntity()
{
PartitionKey = "...",
RowKey = "...",
Minimum = ...,
...
});
Upvotes: 5