---
title: Dependency and unit-of-work registration
summary: Wires core framework services and Oracle/SQL Server NHibernate unit-of-work factories/instances into the consuming application's Autofac container.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Framework.Windows
reference_type: package
operation_id: OP-WIN-005
trigger: Called once from a consuming application's RegisterAppDependencies override.
---

# Dependency and unit-of-work registration

`AutofacExtensions.RegisterCommonDependencies(this ContainerBuilder, string currentUserId, IEnumerable<Assembly> dataClassMapAssemblies, params DatabaseConfig[] configs)` is the single integration point where the DI/composition layer, the data-access subsystem, and core framework services are wired together. A consuming application calls this from its own `RegisterAppDependencies` override (invoked during the [program runner entry point](program-runner-run.md)).

| Field | Value |
| --- | --- |
| **Operation ID** | OP-WIN-005 |
| **Trigger** | Called once per `DatabaseConfig` instance from `AutofacExtensions.RegisterCommonDependencies`, itself called from a consuming application's `RegisterAppDependencies` override. |
| **Inputs** | `currentUserId` (non-null, enforced), optional `dataClassMapAssemblies`, `params DatabaseConfig[] configs`. |
| **Outputs** | Autofac registrations added to the supplied `ContainerBuilder`. |
| **Primary components** | `AutofacExtensions.RegisterCommonDependencies`, `DatabaseConfig.RegisterUnitOfWorkFactories`, `DatabaseConfig.RegisterUnitOfWork` |
| **Entry point** | `Console\SAIF.Console\Console\AutofacExtensions.cs` |

## Steps

1. `Enforce.ArgumentNotNull(currentUserId, "currentUserId")` — throws if `currentUserId` is null ([BR-WIN-013](../business-rules.md#br-win-013-registercommondependencies-requires-non-null-currentuserid)).
2. If `configs != null`: `DatabaseConfig.RegisterUnitOfWorkFactories(builder, dataClassMapAssemblies)` registers three named, `SingleInstance` `IUnitOfWorkFactory` factories:
   - `"oracle"` → `OracleUnitOfWorkFactory(new OracleConfigurationFactory(...))`
   - `"oracleStateless"` → `OracleStatelessUnitOfWorkFactory(new OracleConfigurationFactory(...))`
   - `"sqlSever"` → `SqlServerUnitOfWorkFactory(new SqlServerConfigurationFactory(...))` (typo preserved verbatim from source)
   - Then, for each supplied `DatabaseConfig`, calls `x.RegisterUnitOfWork(builder)` (step 3).
3. Each `DatabaseConfig.RegisterUnitOfWork(builder)` registers, named by `ConfigName` and typed `As<IUnitOfWork>().As<IRepositoryFactory>()`, `InstancePerLifetimeScope`, a factory delegate that:
   - Resolves the named `IUnitOfWorkFactory` (via the subclass's `FactoryName` — [BR-WIN-015](../business-rules.md#br-win-015-sql-server-has-no-stateless-factory-variant) for `SqlServerConfig`, [BR-WIN-016](../business-rules.md#br-win-016-oracle-factory-selection-driven-by-stateless-flag) for `OracleConfig`).
   - Calls `.GetUnitOfWork(connectionString, showSql: ShowSql, batchSize: BatchSize)`, where `connectionString = GetConnectionString(env, env.GetConfigSetting(EnvironmentConfigKey))` (subclass-specific — Oracle uses `DbConnectionManager.GetConnectionStringForInstance`, SQL Server uses `DbConnectionManager.GetConnectionStringForSqlServer`).
4. `ServiceRegistrations.RegisterCoreServicesForWindows(builder, currentUserId)` — external registration call (implementation not in this library).
5. Registers `WindowsEnvironmentService` `As<IEnvironmentService>()`, `InstancePerLifetimeScope`.
6. Registers `ConsoleLogService` `As<IConsoleLogService>()`, `InstancePerLifetimeScope` — this registration is the trigger for [console log service discovery](console-log-service-discovery.md) the first time `IConsoleLogService` is resolved.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([RegisterCommonDependencies called]) --> Enforce[Enforce currentUserId not null]
	Enforce --> ConfigsCheck{configs supplied?}
	ConfigsCheck -->|Yes| Factories[Register oracle / oracleStateless / sqlSever factories]
	Factories --> PerConfig[RegisterUnitOfWork per DatabaseConfig]
	ConfigsCheck -->|No| Core[RegisterCoreServicesForWindows]
	PerConfig --> Core
	Core --> EnvSvc[Register WindowsEnvironmentService as IEnvironmentService]
	EnvSvc --> LogSvc[Register ConsoleLogService as IConsoleLogService]
	LogSvc --> Done([Registrations added to builder])
```

## Failure and edge-case behavior
- A null `currentUserId` throws before any registration is added to the container ([BR-WIN-013](../business-rules.md#br-win-013-registercommondependencies-requires-non-null-currentuserid)).
- No enforcement exists for a null/empty `DatabaseConfig.EnvironmentConfigKey` — such a value is passed straight through to `IEnvironmentService.GetConfigSetting`, with the resulting behavior determined entirely by the external `IEnvironmentService` implementation.*
- `WindowsEnvironmentService` is registered unconditionally; a consuming application cannot override the `IEnvironmentService` implementation without a subsequent overriding registration (last-registration-wins in Autofac).

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Sources
- `Console\SAIF.Console\Console\AutofacExtensions.cs`
- `Console\SAIF.Console\Console\DatabaseConfigs\DatabaseConfig.cs`
- `Console\SAIF.Console\Console\DatabaseConfigs\OracleConfig.cs`
- `Console\SAIF.Console\Console\DatabaseConfigs\SqlServerConfig.cs`
