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 additonal parameters into the constructor. Any other parameters your define will have their values satisfied from the dependency injection container.
internal class MyActor : Actor, IMyActor, IRemindable
{
public MyActor(ActorHost host, BankService bank) // Accept BankService in the constructor
: base(host)
{
...
}
}
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
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<BankService>();
}
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 recieve 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:
public Task<MyData> GetDataAsync()
{
this.Logger.LogInformation("Getting state at {CurrentTime}", DateTime.UtcNow);
return this.StateManager.GetStateAsync<MyData>("my_data");
}
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.
[Actor(TypeName = "MyCustomActorTypeName")]
internal class MyActor : Actor, IMyActor
{
// ...
}
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 (
UseActors
) - 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
:
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
{
...
// Customize JSON options
});
}
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.
// in Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// Register actors handlers that interface with the Dapr runtime.
endpoints.MapActorsHandlers();
});
}
The UseRouting
and UseEndpoints
calls are necessary to configure routing. Adding MapActorsHandlers
inside the endpoint middleware is what configures actors as part of the pipline.
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