ActorTableEntities 2.1.0

dotnet add package ActorTableEntities --version 2.1.0
                    
NuGet\Install-Package ActorTableEntities -Version 2.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ActorTableEntities" Version="2.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ActorTableEntities" Version="2.1.0" />
                    
Directory.Packages.props
<PackageReference Include="ActorTableEntities" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ActorTableEntities --version 2.1.0
                    
#r "nuget: ActorTableEntities, 2.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ActorTableEntities@2.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ActorTableEntities&version=2.1.0
                    
Install as a Cake Addin
#tool nuget:?package=ActorTableEntities&version=2.1.0
                    
Install as a Cake Tool

Actor Table Entities

A play on Azure Functions Durable Entities without the queuing. Locks a blob behind the scenes to ensure the actor can only be amended once, then free us for the next connection.

Build Status NuGet

What's New in v2.0

  • Upgraded to .NET 8.0 LTS - Full support for the latest .NET runtime
  • Azure SDK v12 - Migrated from legacy WindowsAzure.Storage to modern Azure.Data.Tables and Azure.Storage.Blobs
  • Azure Functions v4 - Sample project uses the isolated worker model
  • Aspire Integration - Sample includes .NET Aspire AppHost for local development
  • OpenTelemetry Support - Built-in telemetry via Application Insights
  • Comprehensive Tests - Unit and integration tests included
  • Manual Versioning - Simplified version management in project files

Why not use Durable Entities?

I did, honestly, and yes they are amazing, but for my specific use case they did fit well. I wanted something that was:

  • Quick to respond
  • Wasn't meant for scale on a single entity (Max 10-20 consumers of an entity)
  • Controllable via standard functions
  • Cheaper

Where as durableEntities are great, due to the nature of the queuing involved using Orchestrator functions, it meant when release I could wait or a good few seconds anywhere between 2-10 for my request to complete, then if it did, I would generally have to get a status endpoint to monitor my result.

Next up I attempted to go straight to the Entity and its operations, but the lack of responses from the operations without meaningful HTTP responses stopped me.

So, I built this...

Usage

So this is a typical entity, inheriting from ITableEntity, it will allow you to put complex types as properties, it will also allow for you to interact with the actual entity by claiming a lock just before reading, if it fails to get a lock, it will retry every Xms for X attempts as defined in your config.

public class Counter : ActorTableEntity
{
    public int Count { get; set; }

    public Counter Increment()
    {
        Count = Count + 1;

        return this;
    }
}

You can see a sample function in the main project, but it looks a bit like this.

public class FunctionApis
{
    private readonly IActorTableEntityClient _entityClient;

    public FunctionApis(IActorTableEntityClient entityClient)
    {
        _entityClient = entityClient;
    }

    [Function("UpdateHttpApi")]
    public async Task<IActionResult> Update(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "update/{name}")] HttpRequest req, 
        string name)
    {
        await using var state = await _entityClient.GetLocked<Counter>("entity", name);

        state.Entity.Increment();

        await state.Flush();

        return new OkObjectResult(state.Entity);
    }
}

The code above lets you take a hold of an entity, do some stuff on it, then release the lock, allowing the next punter to take it up.

Setup

Finally, install the nuget package above, and bootstrap your code like so.

The simplest way to get started is to pass your connection string directly. The library uses sensible defaults for all other options:

var host = new HostBuilder()
    .ConfigureFunctionsWebApplication()
    .ConfigureServices(services =>
    {
        services.AddActorTableEntities(
            Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? "UseDevelopmentStorage=true"
        );
    })
    .Build();

host.Run();

This uses the following defaults: | Option | Default Value | |--------|---------------| | ContainerName | "entitylocks" | | StateContainerName | "entitystate" | | WithRetry | true | | RetryIntervalMilliseconds | 100 |

Custom Configuration

If you need to customize the options, you can pass an optional configuration delegate:

services.AddActorTableEntities(
    Environment.GetEnvironmentVariable("AzureWebJobsStorage") ?? "UseDevelopmentStorage=true",
    options =>
    {
        options.ContainerName = "mylocks";
        options.StateContainerName = "mystate";
        options.WithRetry = true;
        options.RetryIntervalMilliseconds = 200;
    }
);

Configuration Options

Option Type Default Description
ContainerName string "entitylocks" Blob container name for distributed locks
StateContainerName string "entitystate" Blob container name for actor state storage
WithRetry bool true Enable retry logic when acquiring locks
RetryIntervalMilliseconds int 100 Interval between retry attempts in milliseconds

State Storage

Actor state is stored as JSON in Azure Blob Storage while metadata (PartitionKey, RowKey, Timestamp, ETag) is kept in Azure Table Storage. This approach provides:

  • Better scalability
  • No serialization limitations from Table Storage
  • Thread-safe operations via the existing blob locking mechanism

Local Development with Aspire

The sample project includes .NET Aspire for easy local development with the Azure Storage emulator:

# Run the Aspire AppHost
cd SampleHttpFunctions.AppHost
dotnet run

This will start:

  • Azure Storage Emulator (Azurite) in a container
  • Sample Azure Functions application
  • Aspire Dashboard for monitoring and logs

Testing

The project includes comprehensive unit and integration tests:

# Run unit tests
dotnet test ActorTableEntities.Tests/ActorTableEntities.Tests.csproj

# Run integration tests (requires Azurite)
dotnet test ActorTableEntities.IntegrationTests/ActorTableEntities.IntegrationTests.csproj

CI/CD with GitHub Actions

The project uses GitHub Actions for continuous integration:

  • PR Build: Runs on all pull requests, executes tests and builds
  • Release: Publishes to NuGet when a tag is pushed (e.g., v2.0.0)

To create a release:

git tag v2.0.0
git push origin v2.0.0

Built with it

Cards Against COVID

Have a play and see what you think, I built this with it:

https://stcardshumanity.z33.web.core.windows.net/

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
2.1.0 164 1/2/2026
2.0.0 92 1/1/2026
1.1.6-alpha-g5bcacaf2f0 649 4/25/2020
1.0.1-beta-g49c2a4a28f 528 4/25/2020
0.1.0-alpha000 547 4/24/2020