# 11 — Akka.Hosting ## Overview Akka.Hosting is the recommended integration layer between Akka.NET and the `Microsoft.Extensions.*` ecosystem (Hosting, DependencyInjection, Configuration, Logging). It replaces the traditional HOCON-only configuration approach with a code-first, type-safe API and provides an `ActorRegistry` for injecting actor references into non-actor services. In our SCADA system, Akka.Hosting is the entry point for bootstrapping the entire ActorSystem — configuring Remoting, Cluster, Singleton, Persistence, and all other modules through a fluent C# API that integrates with the standard .NET Generic Host. ## When to Use - Always — Akka.Hosting should be the primary way to configure and start Akka.NET in any new .NET 10 application - Configuring all Akka.NET modules (Remoting, Cluster, Persistence, etc.) in code rather than HOCON files - Registering top-level actors in the `ActorRegistry` for injection into ASP.NET controllers, Windows Services, or other DI consumers - Managing ActorSystem lifecycle tied to the .NET host lifecycle ## When Not to Use - There are no scenarios where you should avoid Akka.Hosting in new projects on .NET 6+ - Legacy projects on older .NET may need the traditional HOCON approach if they cannot adopt `Microsoft.Extensions.Hosting` ## Design Decisions for the SCADA System ### Windows Service Host The SCADA application runs as a Windows Service using the .NET Generic Host: ```csharp var builder = Host.CreateApplicationBuilder(args); builder.Services.AddAkka("scada-system", (akkaBuilder, sp) => { var siteConfig = sp.GetRequiredService(); akkaBuilder .ConfigureLoggers(loggers => { loggers.LogLevel = Akka.Event.LogLevel.InfoLevel; loggers.AddLoggerFactory(); // Bridge to Microsoft.Extensions.Logging }) .WithRemoting(options => { options.Hostname = "0.0.0.0"; options.PublicHostname = siteConfig.NodeHostname; options.Port = 4053; }) .WithClustering(new ClusterOptions { Roles = new[] { "scada-node" }, SeedNodes = siteConfig.SeedNodes }) .WithSingleton("device-manager", (system, registry, resolver) => resolver.Props(), new ClusterSingletonOptions { Role = "scada-node" }) .WithSingletonProxy("device-manager", new ClusterSingletonProxyOptions { Role = "scada-node" }) .WithDistributedData() .WithActors((system, registry, resolver) => { var healthActor = system.ActorOf( resolver.Props(), "cluster-health"); registry.Register(healthActor); }); }); var host = builder.Build(); await host.RunAsync(); ``` ### ActorRegistry for DI Integration The `ActorRegistry` stores named `IActorRef` instances that can be injected into non-actor services: ```csharp // Registering actors registry.Register(deviceManagerRef); registry.Register(healthActorRef); // Consuming in a Windows Service health check endpoint public class HealthCheckService : IHostedService { private readonly IRequiredActor _healthActor; public HealthCheckService(IRequiredActor healthActor) { _healthActor = healthActor; } public async Task CheckHealthAsync() { var actorRef = await _healthActor.GetAsync(); var status = await actorRef.Ask(new GetHealth(), TimeSpan.FromSeconds(5)); return status.IsHealthy ? HealthStatus.Healthy : HealthStatus.Unhealthy; } } ``` ### Site-Specific Configuration Use `Microsoft.Extensions.Configuration` (appsettings.json, environment variables) for site-specific values (hostnames, seed nodes, device lists). Inject these into the Akka configuration: ```json // appsettings.json { "ScadaSite": { "NodeHostname": "nodeA.scada.local", "SeedNodes": [ "akka.tcp://scada-system@nodeA.scada.local:4053", "akka.tcp://scada-system@nodeB.scada.local:4053" ], "DeviceConfigPath": "C:\\ProgramData\\SCADA\\devices.json" } } ``` ```csharp builder.Services.Configure( builder.Configuration.GetSection("ScadaSite")); ``` ## Common Patterns ### Combining HOCON and Hosting For module-specific settings not yet covered by Hosting APIs, you can mix HOCON with code-first configuration: ```csharp akkaBuilder.AddHocon(ConfigurationFactory.ParseString(@" akka.cluster.split-brain-resolver { active-strategy = keep-oldest keep-oldest.down-if-alone = on stable-after = 15s } "), HoconAddMode.Prepend); ``` ### Logging Bridge Bridge Akka.NET's internal logging to `Microsoft.Extensions.Logging` so all logs go through the same pipeline (Serilog, NLog, etc.): ```csharp akkaBuilder.ConfigureLoggers(loggers => { loggers.ClearLoggers(); loggers.AddLoggerFactory(); }); ``` ### Coordinated Shutdown Integration Akka.Hosting automatically ties `CoordinatedShutdown` to the host's lifetime. When the Windows Service stops, the ActorSystem leaves the cluster gracefully and shuts down. No additional configuration is needed. ## Anti-Patterns ### Bypassing Hosting to Create ActorSystem Manually Do not create `ActorSystem.Create()` alongside Akka.Hosting. This creates a second, unmanaged ActorSystem. Always use `AddAkka()` on the service collection. ### Registering Actors That Don't Exist Yet The `ActorRegistry` resolves asynchronously (`GetAsync()`), but registering an actor reference that is never created will cause consumers to hang indefinitely. Always register actors in the `WithActors` callback where they are created. ### Hardcoding Configuration Do not hardcode hostnames, ports, or seed nodes in the `AddAkka` configuration. Use `Microsoft.Extensions.Configuration` so that each site's deployment can override these values via appsettings.json or environment variables. ## Configuration Guidance ### NuGet Packages ``` Akka.Hosting Akka.Remote.Hosting Akka.Cluster.Hosting (includes Sharding, Tools) Akka.Persistence.Hosting ``` These Hosting packages replace the need to install the base packages separately — they include their dependencies. ### Startup Order Akka.Hosting initializes components in the order they are registered. Register in dependency order: 1. Loggers 2. Remoting 3. Clustering (depends on Remoting) 4. Persistence 5. Distributed Data 6. Singletons and Singleton Proxies (depend on Clustering) 7. Application actors ## References - GitHub / Documentation: - Petabridge Blog: - DI with Akka.NET: