Dapr actor .NET usage guide

    The is a required constructor parameter of all actors, and must be passed to the base class constructor.

    The ActorHost is provided by the runtime and contains all of the state that the allows that actor instance to communicate with the runtime. Since the ActorHost contains state unique to the actor, you should not pass the instance into other parts of your code. You should not create your own instances of ActorHost except in tests.

    Using dependency injection

    Actors support of additional parameters into the constructor. Any other parameters your define will have their values satisfied from the dependency injection container.

    1. internal class MyActor : Actor, IMyActor, IRemindable
    2. {
    3. public MyActor(ActorHost host, BankService bank) // Accept BankService in the constructor
    4. : base(host)
    5. {
    6. ...
    7. }
    8. }

    An actor type should have a single public constructor. The actor infrastructure uses the ActivatorUtilities pattern for constructing actor instances.

    You can register types with dependency injection in Startup.cs to make them available. You can read more about the different ways of registering your types

    1. // In Startup.cs
    2. public void ConfigureServices(IServiceCollection services)
    3. {
    4. ...
    5. services.AddSingleton<BankService>();
    6. }

    Each actor instance has its own dependency injection scope. Each actor remains in memory for some time after performing an operation, and during that time the dependency injection scope associated with the actor is also considered live. The scope will be releases when the actor is deactivated.

    If an actor injects an IServiceProvider in the constructor, the actor will receive a reference to the IServiceProvider associated with its scope. The IServiceProvider can be used to resolve services dynamically in the future.

    When using this pattern, take care to avoid creating many instances of transient services which implement IDisposable. Since the scope associated with an actor could be considered valid for a long time, it is possible to accumulate many services in memory. See the dependency injection guidelines for more information.

    IDisposable and actors

    Inside of an actor class you have access to an instance of through a property on the base Actor class. This instance is connected to the ASP.NET Core logging system, and should be used for all logging inside an actor. Read more about logging here. You can configure a variety of different logging formats and output sinks.

    You should use structured logging with named placeholders like the example below:

    1. public Task<MyData> GetDataAsync()
    2. {
    3. this.Logger.LogInformation("Getting state at {CurrentTime}", DateTime.UtcNow);
    4. return this.StateManager.GetStateAsync<MyData>("my_data");
    5. }

    When logging, avoid using format strings like: $"Getting state at {DateTime.UtcNow}"

    Logging should use the which is more performant and offers better integration with logging systems.

    Using an explicit actor type name

    By default, the type of the actor as seen by clients is derived from the name of the actor implementation class. The default name will be the class name name (without namespace).

    If desired, you can specify an explicit type name by attaching an ActorAttribute attribute to the actor implementation class.

    1. [Actor(TypeName = "MyCustomActorTypeName")]
    2. internal class MyActor : Actor, IMyActor
    3. {
    4. // ...
    5. }

    In the example above the name will be MyCustomActorTypeName.

    No change is needed to the code that registers the actor type with the runtime, providing the value via the attribute is all that is required.

    Hosting actors on the server

    Registering actors

    Inside ConfigureServices you can:

    • Register the actor runtime (AddActors)
    • Register actor types (options.Actors.RegisterActor<>)
    • Configure actor runtime settings options
    • Register additional service types for dependency injection into actors (services)

    The actor runtime uses for serializing data to the state store, and for handling requests from the weakly-typed client.

    By default the actor runtime uses settings based on JsonSerializerDefaults.Web

    You can configure the JsonSerializerOptions as part of ConfigureServices:

    1. // In Startup.cs
    2. public void ConfigureServices(IServiceCollection services)
    3. {
    4. {
    5. ...
    6. // Customize JSON options
    7. });
    8. }

    Actors and routing

    The ASP.NET Core hosting support for actors uses the endpoint routing system. The .NET SDK provides no support hosting actors with the legacy routing system from early ASP.NET Core releases.

    Since actors uses endpoint routing, the actors HTTP handler is part of the middleware pipeline. The following is a minimal example of a Configure method setting up the middleware pipeline with actors.

    1. // in Startup.cs
    2. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    3. {
    4. if (env.IsDevelopment())
    5. {
    6. app.UseDeveloperExceptionPage();
    7. }
    8. app.UseRouting();
    9. app.UseEndpoints(endpoints =>
    10. {
    11. // Register actors handlers that interface with the Dapr runtime.
    12. endpoints.MapActorsHandlers();
    13. });
    14. }

    The UseRouting and UseEndpoints calls are necessary to configure routing. Adding MapActorsHandlers inside the endpoint middleware is what configures actors as part of the pipeline.

    This is a minimal example, it’s valid for Actors functionality to existing alongside:

    • Controllers
    • Razor Pages
    • Blazor
    • gRPC Services
    • Dapr pub/sub handler
    • other endpoints such as health checks

    Problematic middleware