Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Layers
open Axial.Console
open Axial.FileSystem
open Axial.Hosting
open Axial.Hosting.Browser
open Axial.Hosting.Node
open Axial.HttpClient
open Axial.PlatformService
open Axial.Process
open Axial.State
open Axial.Telemetry
open Axial.Telemetry.JavaScript.NET Hosting
Axial.Hosting connects root Flow applications to .NET process and Generic Host lifecycle. It also adapts
Microsoft.Extensions.Logging to the explicit ILog service and provides fiber-defect logging.
dotnet add package Axial.Hosting
The package is optional. App works in console, desktop, test, and embedded applications without
Microsoft.Extensions.Hosting or a dependency-injection container.
Standalone CLI or Script
Use DotNetApp.run when the application owns a console process but does not use Generic Host:
open Axial
open Axial.Hosting
type AppError = | InvalidArguments of string
let describeError = function
| InvalidArguments message -> message
let application : Flow<string array, AppError, unit> =
flow {
let! args = Flow.env<string array, AppError>
if Array.isEmpty args then
return! Flow.fail (InvalidArguments "Supply at least one argument.")
}
[<EntryPoint>]
let main args =
DotNetApp.run describeError args application
.GetAwaiter()
.GetResult()| Exit | Process code |
|---|---|
| Success | 0 |
| Typed failure only | 1 |
| Defect | 2 |
| Interruption | 130 |
A cleanup defect takes precedence when a cause also contains interruption.
It returns the code rather than calling Environment.Exit, so finally blocks and asynchronous finalizers are not
skipped.
Generic Host
Build the application as a Flow whose input is either IServiceProvider or an explicit environment constructed
from it:
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Axial
open Axial.Hosting
let builder = Host.CreateApplicationBuilder(args)
builder.Services.AddSingleton<IOrderRepository, SqlOrderRepository>()
|> ignore
let application : Flow<AppEnv, AppError, unit> =
program
|> Layer.provide Live.appLayer
builder.Services
|> Hosting.addApp
(fun services ->
{ Orders = services.GetRequiredService<IOrderRepository>() })
AppError.describe
application
|> ignore
builder.Build().Run()- Constructs the explicit environment when the host starts.
- Starts one root
App. - Connects
IHostApplicationLifetime.ApplicationStoppingto coordinated stop. - Logs success, typed failure, interruption, or defects through the host logger.
- Requests host shutdown when the finite root application completes.
- Waits for root cleanup from
StopAsync.
Use Hosting.addAppWith { StopHostOnCompletion = false } when the root Flow is one hosted participant and another
hosted service owns process completion.
IServiceProvider stays at the application edge. Prefer constructing an explicit record or providing a Layer before
domain workflows run. See Providing the environment.
Microsoft Logging as ILog
Create the explicit Axial logging service from an existing logger:
let axialLog : ILog =
MicrosoftLogging.create loggerlet axialLog : ILog =
MicrosoftLogging.fromFactory "MyApp" loggerFactoryFiber Defect Logging
Install the observer once around the root application:
let observed =
application
|> FiberLogging.observe loggerapplication
|> Flow.withFiberObserver
(FiberObserver.compose
FiberTelemetry.observerWithSpans
(FiberLogging.observer logger))Desktop and Embedded Applications
Desktop frameworks already own application lifetime. Start App after startup and await stop from the framework's
closing path:
let running = App.start environment application
let closeApplication () = async {
let! _ = running.Stop()
dispatcher.RequestExit()
}Other Runtimes
- Node hosting handles Node arguments,
process.env, signals, and exit status. - Browser hosting handles explicit UI ownership and
AbortSignal.

