# Dependency Injection - Assembly Scanning Guide ## 🎯 Overview This project uses **assembly scanning** to automatically register services instead of manual registration. This means you don't need to add each service to `Program.cs` individually. --- ## 🔍 How It Works ### In `Program.cs` ```csharp // These two lines register ALL services automatically builder.Services.AddDataServices(); // Scans SeaHaven.DataServices assembly builder.Services.AddBusinessServices(); // Scans SeaHaven.Services assembly + Validators ``` That's it! No need for this: ```csharp // ❌ DON'T DO THIS - It's automatic now! builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // ... hundreds of lines ``` --- ## 📦 DataServicesModule **Location**: `SeaHaven.DataServices/DependencyInjection/DataServicesModule.cs` ```csharp public static IServiceCollection AddDataServices(this IServiceCollection services) { var assembly = Assembly.GetExecutingAssembly(); // Find all non-abstract classes in the assembly var allClasses = assembly.GetTypes() .Where(t => t.IsClass && !t.IsAbstract && !t.IsGenericType) .ToList(); foreach (var implementationType in allClasses) { // Find interface matching pattern: I{ClassName} var defaultInterface = implementationType.GetInterfaces() .FirstOrDefault(i => i.Name == $"I{implementationType.Name}"); if (defaultInterface != null) { // Register as Scoped services.AddScoped(defaultInterface, implementationType); } } return services; } ``` ### What It Does 1. Scans entire `SeaHaven.DataServices` assembly 2. Finds all concrete classes (e.g., `ContactDataService`, `EmployeeDataService`) 3. For each class, looks for an interface named `I{ClassName}` 4. If found, registers the pair as **Scoped** service ### Example If you create: - `IProductDataService` (interface) - `ProductDataService` (class implementing `IProductDataService`) Then `IProductDataService → ProductDataService` is **automatically registered** as Scoped. --- ## 💼 ServicesModule **Location**: `SeaHaven.Services/DependencyInjection/ServicesModule.cs` ```csharp public static IServiceCollection AddBusinessServices(this IServiceCollection services) { var assembly = Assembly.GetExecutingAssembly(); var allClasses = assembly.GetTypes() .Where(t => t.IsClass && !t.IsAbstract && !t.IsGenericType) .ToList(); foreach (var implementationType in allClasses) { var defaultInterface = implementationType.GetInterfaces() .FirstOrDefault(i => i.Name == $"I{implementationType.Name}"); if (defaultInterface != null) { services.AddScoped(defaultInterface, implementationType); } } // ALSO auto-register all FluentValidation validators services.AddValidatorsFromAssembly(assembly); return services; } ``` ### What It Does 1. Scans entire `SeaHaven.Services` assembly 2. Registers all services using naming convention (same as DataServices) 3. **BONUS**: Automatically registers ALL FluentValidation validators in the assembly ### Example If you create: - `IProductService` (interface) - `ProductService` (class) - `CreateProductDTOValidator` (FluentValidation validator) Then **all three** are automatically registered. --- ## ⚠️ CRITICAL: Naming Convention For auto-registration to work, you MUST follow this pattern: ### ✅ CORRECT | Interface | Implementation | Result | |-----------|---------------|--------| | `IContactService` | `ContactService` | ✅ Registered as Scoped | | `IContactDataService` | `ContactDataService` | ✅ Registered as Scoped | | `IProductService` | `ProductService` | ✅ Registered as Scoped | | `IEmployeeService` | `EmployeeService` | ✅ Registered as Scoped | ### ❌ WRONG | Interface | Implementation | Result | |-----------|---------------|--------| | `IProductService` | `ProductServiceImpl` | ❌ NOT registered - names don't match | | `IContactRepository` | `ContactService` | ❌ NOT registered - names don't match | | `ISomething` | `SomethingElse` | ❌ NOT registered - names don't match | --- ## 📋 Rules 1. **Interface naming**: `I{ClassName}` 2. **Class naming**: `{ClassName}` 3. **Example**: - Interface: `IContactService` - Class: `ContactService` (NOT `ContactServiceImpl`, `ContactServiceImplementation`, etc.) --- ## 🚀 Benefits ✅ **Less boilerplate** - No need to add each service to `Program.cs` ✅ **Auto-discovery** - New services are automatically registered ✅ **Consistent** - All services registered the same way ✅ **FluentValidation included** - Validators work automatically ✅ **Cleaner Program.cs** - Only 2 lines instead of 50+ --- ## 🎯 How to Add a New Service ### Old Way (Manual) ```csharp // 1. Create interface and class public interface IProductService { } public class ProductService : IProductService { } // 2. Manually add to Program.cs builder.Services.AddScoped(); // ❌ DON'T DO THIS ``` ### New Way (Automatic) ```csharp // 1. Create interface and class following naming convention public interface IProductService { } public class ProductService : IProductService { } // 2. Done! It's automatically registered ✅ ``` --- ## 🔧 Lifecycle All services are registered as **Scoped**: - New instance per HTTP request - Shared within the same request - Disposed at end of request --- ## 📚 Example Flow 1. You create `IProductDataService` and `ProductDataService` in `SeaHaven.DataServices` 2. You create `IProductService` and `ProductService` in `SeaHaven.Services` 3. You create `CreateProductDTOValidator` in `SeaHaven.Services/Validation` 4. Application starts → `AddDataServices()` and `AddBusinessServices()` run 5. Assembly scanner finds your services and validator 6. All registered automatically as Scoped 7. You inject `IProductService` in controller → works immediately ✅ --- ## 🐛 Troubleshooting ### Service not being injected? Check: 1. ✅ Is the interface named `I{ClassName}`? 2. ✅ Is the class named `{ClassName}`? 3. ✅ Is the class in the correct assembly? 4. ✅ Is the class public and concrete (not abstract)? 5. ✅ Does the class implement the interface? ### Validator not working? Check: 1. ✅ Is the validator in `SeaHaven.Services` assembly? 2. ✅ Does it inherit from `AbstractValidator`? 3. ✅ Is it public and concrete? --- ## 📖 See Also - **Full Architecture Guide**: `BACKEND_ARCHITECTURE.md` - **Quick Start Guide**: `QUICK_START_GUIDE.md` - **At a Glance**: `ARCHITECTURE_AT_A_GLANCE.md`