# Container Feature Integration Guide ## Overview This guide demonstrates how the Container's three major features work together to provide powerful dependency management: 1. Contextual Binding - Different implementations based on context 2. Method Injection - Automatic dependency resolution for methods 3. Tagged Bindings - Grouping related services ## Real World Example: Multi-tenant Reporting System Let's build a complete multi-tenant reporting system that showcases all three features working together. ### System Requirements 1. Multiple tenants (clients) each need their own: - Database connection - Storage system - Report formatting 2. Various types of reports: - Performance reports - Financial reports - User activity reports 3. Each report needs: - Data access - Formatting - Storage - Logging ### Base Interfaces ```dart /// Base interface for all reports abstract class Report { Future generate(); Future save(); } /// Database connection interface abstract class Database { Future>> query(String sql); } /// Storage system interface abstract class Storage { Future save(String path, List data); Future> load(String path); } /// Report formatter interface abstract class ReportFormatter { String format(Map data); } ``` ### Tenant-Specific Implementations ```dart /// Tenant A's database implementation class TenantADatabase implements Database { @override Future>> query(String sql) { // Tenant A specific database logic } } /// Tenant B's database implementation class TenantBDatabase implements Database { @override Future>> query(String sql) { // Tenant B specific database logic } } /// Similar implementations for Storage and Formatter... ``` ### Report Implementations ```dart class PerformanceReport implements Report { final Database db; final Storage storage; final ReportFormatter formatter; PerformanceReport(this.db, this.storage, this.formatter); @override Future generate() async { var data = await db.query('SELECT * FROM performance_metrics'); var formatted = formatter.format(data); await storage.save('performance.report', formatted.codeUnits); } } // Similar implementations for Financial and UserActivity reports... ``` ### Using All Three Features Together 1. First, set up contextual bindings for tenant-specific services: ```dart void configureTenantA(Container container) { // Bind tenant-specific implementations container.when(TenantAContext) .needs() .give(TenantADatabase()); container.when(TenantAContext) .needs() .give(TenantAStorage()); container.when(TenantAContext) .needs() .give(TenantAFormatter()); } void configureTenantB(Container container) { // Similar bindings for Tenant B... } ``` 2. Set up tagged bindings for reports: ```dart void configureReports(Container container) { // Bind report implementations container.bind(PerformanceReport); container.bind(FinancialReport); container.bind(UserActivityReport); // Tag them for easy retrieval container.tag([ PerformanceReport, FinancialReport, UserActivityReport ], 'reports'); // Additional tags for categorization container.tag([PerformanceReport], 'metrics-reports'); container.tag([FinancialReport], 'financial-reports'); } ``` 3. Create a report manager that uses method injection: ```dart class ReportManager { final Container container; ReportManager(this.container); /// Generates all reports for a tenant /// Uses method injection for the logger parameter Future generateAllReports( TenantContext tenant, {required DateTime date} ) async { // Get all tagged reports var reports = container.taggedAs('reports'); // Generate each report using tenant context for (var report in reports) { await container.call( report, 'generate', parameters: {'date': date}, context: tenant // Uses contextual binding ); } } /// Generates specific report types /// Uses method injection for dependencies Future generateMetricsReports( TenantContext tenant, Logger logger, // Injected automatically MetricsService metrics // Injected automatically ) async { var reports = container.taggedAs('metrics-reports'); for (var report in reports) { logger.info('Generating metrics report: ${report.runtimeType}'); await container.call(report, 'generate', context: tenant); metrics.recordReportGeneration(report); } } } ``` ### Using the Integrated System ```dart void main() async { var container = Container(); // Configure container configureTenantA(container); configureTenantB(container); configureReports(container); // Create report manager var manager = ReportManager(container); // Generate reports for Tenant A await manager.generateAllReports( TenantAContext(), date: DateTime.now() ); // Generate only metrics reports for Tenant B await manager.generateMetricsReports( TenantBContext() ); } ``` ## How the Features Work Together 1. **Contextual Binding** ensures: - Each tenant gets their own implementations - Services are properly scoped - No cross-tenant data leakage 2. **Method Injection** provides: - Automatic dependency resolution - Clean method signatures - Flexible parameter handling 3. **Tagged Bindings** enable: - Easy service grouping - Dynamic service discovery - Flexible categorization ## Common Integration Patterns 1. **Service Location with Context** ```dart // Get tenant-specific service var db = container.make(context: tenantContext); // Get all services of a type for a tenant var reports = container.taggedAs('reports') .map((r) => container.make(r, context: tenantContext)) .toList(); ``` 2. **Method Injection with Tags** ```dart Future processReports(Logger logger) async { // Logger is injected, reports are retrieved by tag var reports = container.taggedAs('reports'); for (var report in reports) { logger.info('Processing ${report.runtimeType}'); await container.call(report, 'process'); } } ``` 3. **Contextual Services with Tags** ```dart Future generateTenantReports(TenantContext tenant) async { // Get all reports var reports = container.taggedAs('reports'); // Process each with tenant context for (var report in reports) { await container.call( report, 'generate', context: tenant ); } } ``` ## Best Practices 1. **Clear Service Organization** ```dart // Group related tags container.tag([Service1, Service2], 'data-services'); container.tag([Service1], 'cacheable-services'); // Group related contexts container.when(TenantContext) .needs() .give(TenantDatabase()); ``` 2. **Consistent Dependency Resolution** ```dart // Prefer method injection for flexible dependencies Future processReport( Report report, Logger logger, // Injected MetricsService metrics // Injected ) async { // Implementation } // Use contextual binding for tenant-specific services container.when(TenantContext) .needs() .give(TenantStorage()); ``` 3. **Documentation** ```dart /// Report processor that handles multiple report types /// /// Uses the following container features: /// - Tagged bindings for report retrieval ('reports' tag) /// - Contextual binding for tenant-specific services /// - Method injection for logging and metrics class ReportProcessor { // Implementation } ``` ## Testing Integrated Features ```dart void main() { group('Integrated Container Features', () { late Container container; setUp(() { container = Container(); // Set up test bindings configureTenantA(container); configureReports(container); }); test('should handle tenant-specific tagged services', () { var tenantA = TenantAContext(); // Get all reports for tenant var reports = container.taggedAs('reports') .map((r) => container.make(r, context: tenantA)) .toList(); expect(reports, hasLength(3)); expect(reports.every((r) => r.db is TenantADatabase), isTrue); }); test('should inject dependencies with context', () async { var processor = ReportProcessor(); var tenantA = TenantAContext(); await container.call( processor, 'processReports', context: tenantA ); // Verify correct services were injected verify(() => processor.logger is Logger).called(1); verify(() => processor.db is TenantADatabase).called(1); }); }); } ``` ## Next Steps 1. Implement integration tests 2. Add performance monitoring 3. Add dependency validation 4. Create usage documentation 5. Add debugging tools 6. Create migration guides Would you like me to create detailed specifications for any of these next steps?