I have the following class:
public class MyData
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public int NumOranges { get; set; }
public int NumApples { get; set; }
public int NumBananas { get; set; }
}
I am writing instances to Azure Table Storage using the .NET 8 Isolated Azure Functions TableOutput
binding.
When I attempt to read the data using Azure.Data.Table.TableClient
(v12.10.0) like this:
var result = tableClient.Query<MyData>(filter: d => d.PartitionKey = 'val');
I get Unable to cast object of type 'System.String' to type 'System.Int32'
errors.
I though table storage was schema-less.
If I change the type of all my int
properties to long
then it works. I can use that as a workaround but I would love to know the cause and if I can do something more preventative or logical about it.
The issue is not to do with the actual values. All values are well within the Int32.MaxValue
. I have double-checked by getting the data as TableEntity
and checked the Max()
of each property.
Azure Table Storage stores numbers as long (Edm.Int64)
, so I have used Convert.ToInt32(entity["PropertyName"])
to read them as int
and avoid type mismatches.
ReadFromTableStorage.cs :
using System.Net;
using Azure.Data.Tables;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using Azure;
using FunctionApp28.Models;
namespace FunctionApp28.Functions
{
public static class ReadFromTableStorage
{
[Function("ReadFromTableStorage")]
public static async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("ReadFromTableStorage");
logger.LogInformation("Reading from Azure Table Storage...");
string connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
string tableName = "kamtable";
if (string.IsNullOrEmpty(connectionString))
{
logger.LogError("AzureWebJobsStorage connection string is missing.");
var errorResponse = req.CreateResponse(HttpStatusCode.InternalServerError);
await errorResponse.WriteStringAsync("Storage connection string not found.");
return errorResponse;
}
try
{
var tableClient = new TableClient(connectionString, tableName);
Pageable<TableEntity> entities = tableClient.Query<TableEntity>();
var resultList = new List<MyData>();
foreach (var entity in entities)
{
resultList.Add(new MyData
{
PartitionKey = entity.PartitionKey,
RowKey = entity.RowKey,
NumOranges = entity.ContainsKey("NumOranges") ? Convert.ToInt32(entity["NumOranges"]) : 0,
NumApples = entity.ContainsKey("NumApples") ? Convert.ToInt32(entity["NumApples"]) : 0,
NumBananas = entity.ContainsKey("NumBananas") ? Convert.ToInt32(entity["NumBananas"]) : 0
});
}
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync(JsonSerializer.Serialize(resultList));
return response;
}
catch (Exception ex)
{
logger.LogError($"Error reading from Table Storage: {ex.Message}");
var errorResponse = req.CreateResponse(HttpStatusCode.InternalServerError);
await errorResponse.WriteStringAsync($"Error retrieving data: {ex.Message}");
return errorResponse;
}
}
}
}
WriteToTableStorage.cs :
using System.Net;
using Azure.Data.Tables;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using FunctionApp28.Models;
namespace FunctionApp28.Functions
{
public static class WriteToTableStorage
{
private const string TableName = "kamtable";
[Function("WriteToTableStorage")]
public static async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req,
FunctionContext context)
{
var logger = context.GetLogger("WriteToTableStorage");
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
var data = JsonConvert.DeserializeObject<MyData>(requestBody);
if (data == null)
{
var badResponse = req.CreateResponse(HttpStatusCode.BadRequest);
await badResponse.WriteStringAsync("Invalid request payload.");
return badResponse;
}
string connectionString = Environment.GetEnvironmentVariable("AzureWebJobsStorage");
var tableClient = new TableClient(connectionString, TableName);
await tableClient.CreateIfNotExistsAsync();
var entity = new TableEntity(data.PartitionKey, data.RowKey)
{
{ "NumOranges", data.NumOranges },
{ "NumApples", data.NumApples },
{ "NumBananas", data.NumBananas }
};
await tableClient.AddEntityAsync(entity);
logger.LogInformation("Data written to table storage successfully.");
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync("Entity written to Table Storage.");
return response;
}
}
}
MyData.cs :
namespace FunctionApp28.Models
{
public class MyData
{
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public int NumOranges { get; set; }
public int NumApples { get; set; }
public int NumBananas { get; set; }
}
}
Output :
I have sent the below POST request.
{
"PartitionKey": "Fruit",
"RowKey": "123",
"NumOranges": 5,
"NumApples": 10,
"NumBananas": 3
}