--- name: keyed-service description: Enforces C# keyed-service constructor parameter naming based on the keyed service name, not the interface type, using the key's final segment and appropriate Query/Command suffixes in camelCase. --- # modul-connect/naming-conventions/keyed-service ## C# Keyed Service Naming Convention Håkan testar ### Rule Definition When generating or refactoring C# constructors using the `[FromKeyedServices]` attribute, the parameter name **must** be derived from the **Key Argument** rather than the **Interface Type**. ### Logic & Transformation 1. **Source of Truth:** Use the value inside `[FromKeyedServices(...)]` (e.g., `ModulConnect.Queries.Postgres.Backoffice`). 2. **Identifier Extraction:** Take the last segment of the Key (e.g., `Backoffice`). 3. **Contextual Suffixing:** - If the namespace contains `.Queries.`, append `Query`. - If the namespace contains `.Commands.`, append `Command`. 4. **Casing:** Convert the result to `camelCase` for the parameter and `_camelCase` for the private field. ### Examples #### ✅ Correct (Key-Derived) ```csharp public class OrderProcessor( [FromKeyedServices(ModulConnect.Queries.Postgres.Backoffice)] IDataAccess backofficeQuery) { private readonly IDataAccess _backofficeQuery = backofficeQuery; } ``` #### ❌ Incorrect (Type-Derived) ```csharp // DO NOT use the interface name "dataAccess" public class OrderProcessor( [FromKeyedServices(ModulConnect.Queries.Postgres.Backoffice)] IDataAccess dataAccess) { /* ... */ } ``` ### Rationale In a modular architecture, the interface (e.g., `IDataAccess`) defines the *contract*, but the Key defines the *instance's specific responsibility*. Naming the parameter after the Key prevents naming collisions when multiple implementations of the same interface are injected and provides immediate semantic clarity.