WebGate.Azure.TableUtils
10.0.0
See the version list below for details.
dotnet add package WebGate.Azure.TableUtils --version 10.0.0
NuGet\Install-Package WebGate.Azure.TableUtils -Version 10.0.0
<PackageReference Include="WebGate.Azure.TableUtils" Version="10.0.0" />
<PackageVersion Include="WebGate.Azure.TableUtils" Version="10.0.0" />
<PackageReference Include="WebGate.Azure.TableUtils" />
paket add WebGate.Azure.TableUtils --version 10.0.0
#r "nuget: WebGate.Azure.TableUtils, 10.0.0"
#:package WebGate.Azure.TableUtils@10.0.0
#addin nuget:?package=WebGate.Azure.TableUtils&version=10.0.0
#tool nuget:?package=WebGate.Azure.TableUtils&version=10.0.0
WebGate.Azure.TableUtils
Extensions for Azure.Data.Tables with typed CRUD clients. Supports complex nested entities, arrays, and IEnumerable via flattened table properties.
The main focus is usage in Azure Functions. Table access uses a Storage Account connection string. SAS and other authentication methods are not supported yet, but can be added when required.
Package: WebGate.Azure.TableUtils
License: Apache-2.0
dotnet add package WebGate.Azure.TableUtils
Target Framework & Versioning
| Target Framework | net10.0 |
| Package version | 10.x.x |
The NuGet package major version matches the .NET target framework major version.
net10.0→ package version10.x.x- A future uplift to
net11.0would start at package version11.0.0
Within a major line, use minor/patch for library changes that stay on the same TFM.
Entity mapping
POCOs are mapped to Azure Table properties by reflection:
- Readable/writable properties are included.
- Nested objects are flattened with
_as separator (Parent.Child→ columnParent_Child). nullproperty values are skipped on serialize.- Value types,
string, andbyte[]are stored directly. - Dedicated converters handle enums, TimeSpan, decimal (InvariantCulture string), arrays, and IEnumerable (JSON via Newtonsoft.Json).
ObjectSerializer (POCO → properties) and ObjectBuilder (TableEntity → POCO) implement this mapping. Clients use them automatically.
ExtendedAzureTableClientService
Registers and resolves TypedAzureTableClient<T> and MultiEntityAzureTableClient instances.
Create a service
var connectionString = "MY_STRING";
var extendedTableService = new ExtendedAzureTableClientService(connectionString);
Initialize the service in Startup / Program.cs of an Azure Function (or host).
Register TypedAzureTableClients
One table per POCO type:
var simplePocoAzureTableClient = extendedTableService.CreateAndRegisterTableClient<SimplePoco>("simplePocoTable");
var parentPocoAzureTableClient = extendedTableService.CreateAndRegisterTableClient<ParentPoco>("parentPocoTable");
Register an already initialized TableClient
extendedTableService.AddInitializedTableClient<SimplePoco>(existingTableClient);
Resolve a TypedAzureTableClient
var simplePocoAzureTableClient = extendedTableService.GetTypedTableClient<SimplePoco>();
Throws ArgumentOutOfRangeException if the type was not registered.
Register a MultiEntityAzureTableClient
Store different entity types in one table. Row keys are prefixed with the registered type name (or a custom prefix):
var multiEntityTableClient = extendedTableService.CreateAndRegisterMultiEntityTableClient("allpocos");
multiEntityTableClient.RegisterType<SimplePoco>();
multiEntityTableClient.RegisterType<MainWithParent>("mwp");
multiEntityTableClient.RegisterType<PocoWithListChildren>();
SimplePoco and PocoWithListChildren use their type name as prefix; MainWithParent uses mwp.
Resolve a MultiEntityAzureTableClient
var multiEntityTableClient = extendedTableService.GetMultiEntityAzureTableClientByTableName("allpocos");
The table name used at registration is the lookup key.
TableEntityResult<T>
Results from both clients are wrapped in TableEntityResult<T>. For TypedAzureTableClient<T>, T is the POCO type. For MultiEntityAzureTableClient list queries, T is object.
public class TableEntityResult<T>(ITableEntity tableEntity, T entity)
{
public string RowKey { get; set; } = tableEntity.RowKey;
public string PartitionKey { set; get; } = tableEntity.PartitionKey;
public ETag ETag { get; set; } = tableEntity.ETag;
public DateTimeOffset? Timestamp { get; set; } = tableEntity.Timestamp;
public T Entity { get; set; } = entity;
}
TypedAzureTableClient<T>
Decorator around Azure.Data.Tables.TableClient with POCO serialize/deserialize (including nested entities, arrays, and IEnumerable).
Get from service
var typedTableClient = extendedTableService.GetTypedTableClient<MyPoco>();
Initialize inline
var connectionString = "MY_STRING";
var tableClient = new TableClient(connectionString, "MyPoco"); // Azure.Data.Tables
await tableClient.CreateIfNotExistsAsync();
var typedTableClient = new TypedAzureTableClient<MyPoco>(tableClient);
Underlying SDK client: typedTableClient.TableClient (GetTableClient() is obsolete).
Preferred 10.x surface: upserts + gets (serialize/deserialize). Use TableClient for deletes and other raw SDK calls.
Examples below use a client bound to MyPoco.
GetAllAsync()
List<TableEntityResult<MyPoco>> pocos = await typedTableClient.GetAllAsync();
All rows; no partition filter.
GetAllAsync(string partitionKey)
List<TableEntityResult<MyPoco>> pocos = await typedTableClient.GetAllAsync("mypoco");
All rows for the given partition key.
GetByIdAsync(string id)
TableEntityResult<MyPoco>? poco = await typedTableClient.GetByIdAsync("1018301");
Looks up by row key id. Partition key is typeof(T).ToString() (typically the full type name, e.g. MyNamespace.MyPoco). Returns null if not found.
GetByIdAsync(string rowKey, string partitionKey)
TableEntityResult<MyPoco>? poco = await typedTableClient.GetByIdAsync("9201u819", "mypoco");
Returns null if not found.
GetAllByQueryAsync(string? query) — obsolete
Prefer GetAllAsync / GetAllAsync(partitionKey). For custom OData filters, query with TableClient.QueryAsync and map via TableEntityResult<T>.BuildTableEntityResult<T>(…).
InsertOrMergeAsync(string rowKey, string partitionKey, object obj)
MyPoco poco = new MyPoco();
// populate poco
Azure.Response result = await typedTableClient.InsertOrMergeAsync("001", "SimplePoco", poco);
Upsert with TableUpdateMode.Merge. The parameter is object so partial DTOs (not necessarily T) can be merged.
InsertOrReplaceAsync(string rowKey, string partitionKey, object obj)
MyPoco poco = new MyPoco();
// populate poco
Azure.Response result = await typedTableClient.InsertOrReplaceAsync("001", "SimplePoco", poco);
Upsert with TableUpdateMode.Replace.
DeleteEntityAsync — obsolete (compile error)
Parameter order is reversed vs the Azure SDK:
| 1st arg | 2nd arg | |
|---|---|---|
| This library (obsolete) | rowKey |
partitionKey |
TableClient.DeleteEntityAsync |
partitionKey |
rowKey |
// old:
await typedTableClient.DeleteEntityAsync("001", "SimplePoco");
// new:
await typedTableClient.TableClient.DeleteEntityAsync("SimplePoco", "001");
MultiEntityAzureTableClient
Decorator around TableClient with the same mapping capabilities, plus multiple entity types in one table. Each registered type gets a row-key prefix ({prefix}_{rowKey}). Types must be registered before insert/get-by-type. Unregistered row prefixes on read throw ArgumentOutOfRangeException.
Get from service
var multiEntityTableClient = extendedTableService.GetMultiEntityAzureTableClientByTableName("allpocos");
Initialize inline
var connectionString = "MY_STRING";
var tableClient = new TableClient(connectionString, "allpocos"); // Azure.Data.Tables
await tableClient.CreateIfNotExistsAsync();
var multiEntityTableClient = new MultiEntityAzureTableClient(tableClient);
multiEntityTableClient.RegisterType<SimplePoco>();
multiEntityTableClient.RegisterType<MainWithParent>("mwp");
multiEntityTableClient.RegisterType<PocoWithListChildren>();
Underlying SDK client: multiEntityTableClient.TableClient (GetTableClient() is obsolete).
Preferred 10.x surface: registry + upserts + gets (+ DeleteEntityByTypeAsync for prefix-aware delete). Raw delete by full row key: TableClient.DeleteEntityAsync.
Examples below assume SimplePoco, MainWithParent, and PocoWithListChildren are registered.
GetAllAsync()
List<TableEntityResult<object>> allPocos = await multiEntityTableClient.GetAllAsync();
List<SimplePoco> simplePocos = allPocos.Select(res => res.Entity).OfType<SimplePoco>().ToList();
GetAllAsync(string partitionKey)
List<TableEntityResult<object>> allPocos = await multiEntityTableClient.GetAllAsync("mypoco");
List<SimplePoco> simplePocos = allPocos.Select(res => res.Entity).OfType<SimplePoco>().ToList();
GetByIdAsync<T>(string rowKey, string partitionKey)
TableEntityResult<MyPoco>? poco = await multiEntityTableClient.GetByIdAsync<MyPoco>("9201u819", "mypoco");
Resolves the stored row key as {registeredPrefix}_{rowKey}. Returns null if not found. Throws if T is not registered.
GetAllByQueryAsync(string? query)
var query = $"PartitionKey eq '{partitionKey}'";
List<TableEntityResult<object>> allPocos = await multiEntityTableClient.GetAllByQueryAsync(query);
List<SimplePoco> simplePocos = allPocos.Select(res => res.Entity).OfType<SimplePoco>().ToList();
OData filter as supported by TableClient.QueryAsync. Pass null for an unfiltered query. Needed here so row keys are still resolved via the type registry.
InsertOrMergeAsync<T>(string rowKey, string partitionKey, T obj)
MyPoco poco = new MyPoco();
// populate poco
Azure.Response result = await multiEntityTableClient.InsertOrMergeAsync("001", "SimplePoco", poco);
Stores row key as {prefix}_001. Type of obj must be registered.
InsertOrReplaceAsync<T>(string rowKey, string partitionKey, T obj)
MyPoco poco = new MyPoco();
// populate poco
Azure.Response result = await multiEntityTableClient.InsertOrReplaceAsync("001", "SimplePoco", poco);
DeleteEntityByTypeAsync<T>(string rowKey, string partitionKey)
Azure.Response result = await multiEntityTableClient.DeleteEntityByTypeAsync<SimplePoco>("001", "SimplePoco");
Builds the row key from the registered prefix for T. Prefer this when you know the entity type.
DeleteEntityAsync(completeRowKey, partitionKey) — obsolete (compile error)
Parameter order is reversed vs the Azure SDK:
| 1st arg | 2nd arg | |
|---|---|---|
| This library (obsolete) | completeRowKey |
partitionKey |
TableClient.DeleteEntityAsync |
partitionKey |
rowKey |
// old:
await multiEntityTableClient.DeleteEntityAsync(result.RowKey, result.PartitionKey);
// new:
await multiEntityTableClient.TableClient.DeleteEntityAsync(result.PartitionKey, result.RowKey);
License
Apache-2.0
Copyright
2026, WebGate Consulting AG
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Azure.Data.Tables (>= 12.11.0)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 10.1.0 | 92 | 8/31/2026 |
| 10.0.0 | 110 | 8/3/2026 |
| 0.1.1 | 1,695 | 5/16/2024 |
| 0.1.0 | 203 | 5/16/2024 |
| 0.1.0-alpha-1 | 218 | 4/29/2024 |