using Microsoft.Extensions.DependencyInjection; namespace Toolkit.Foundation; public static class IServiceCollectionExtensions { public static IServiceCollection AddAsyncHandler(this IServiceCollection services, string key) where THandler : class, IAsyncHandler where TMessage : class => AddAsyncHandler(services, ServiceLifetime.Transient, key); public static IServiceCollection AddAsyncHandler(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IAsyncHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), key, typeof(THandler), lifetime)); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), typeof(THandler), lifetime)); services.AddInitialization>>(); } return services; } public static IServiceCollection AddAsyncHandler(this IServiceCollection services, string key) where THandler : class, IAsyncHandler where TMessage : class => AddAsyncHandler(services, ServiceLifetime.Transient, key); public static IServiceCollection AddAsyncHandler(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IAsyncHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), key, typeof(THandler), lifetime)); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), typeof(THandler), lifetime)); services.AddInitialization>>(); } return services; } public static IServiceCollection AddAsyncHandlerScoped(this IServiceCollection services, string key) where THandler : class, IAsyncHandler where TMessage : class => AddAsyncHandlerScoped(services, ServiceLifetime.Transient, key); public static IServiceCollection AddAsyncHandlerScoped(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IAsyncHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), key, typeof(THandler), lifetime)); services.AddInitializationScoped>>(key); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), typeof(THandler), lifetime)); services.AddInitializationScoped>>(); services.AddInitialization>>(); } return services; } public static IServiceCollection AddAsyncHandlerScoped(this IServiceCollection services, string key) where THandler : class, IAsyncHandler where TMessage : class => AddAsyncHandlerScoped(services, ServiceLifetime.Transient, key); public static IServiceCollection AddAsyncHandlerScoped(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IAsyncHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), key, typeof(THandler), lifetime)); services.AddInitializationScoped>>(key); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IAsyncHandler), typeof(THandler), lifetime)); services.AddInitializationScoped>>(); services.AddInitialization>>(); } return services; } public static IServiceCollection AddAsyncInitialization(this IServiceCollection services) where TInitialization : class, IAsyncInitialization { services.AddTransient(); return services; } public static IServiceCollection AddAsyncPipelineBehavior(this IServiceCollection services, Type behaviorType, string? key = null) { bool ImplementsInterface(Type type, Type interfaceType) => type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType); if (ImplementsInterface(behaviorType, typeof(IAsyncPipelineBehavior<,>))) { if (key is { Length: > 0 }) { services.AddKeyedTransient(typeof(IAsyncPipelineBehavior<,>), key, behaviorType); } else { services.AddTransient(typeof(IAsyncPipelineBehavior<,>), behaviorType); } } if (ImplementsInterface(behaviorType, typeof(IAsyncPipelineBehavior<>))) { if (key is { Length: > 0 }) { services.AddKeyedTransient(typeof(IAsyncPipelineBehavior<>), key, behaviorType); } else { services.AddTransient(typeof(IAsyncPipelineBehavior<>), behaviorType); } } return services; } public static IServiceCollection AddCache(this IServiceCollection services) where TKey : notnull where TValue : notnull { services.AddScoped, Cache>(); services.AddTransient(provider => provider.GetService>()!.Select(x => x.Value)); return services; } public static IServiceCollection AddCache(this IServiceCollection services) { services.AddSingleton, Cache>(); services.AddTransient(provider => provider.GetService>()!.Select(x => x)); return services; } public static IServiceCollection AddComponent(this IServiceCollection services) where TComponent : class, IComponent { services.AddTransient(); return services; } public static IServiceCollection AddHandler(this IServiceCollection services, string key) where THandler : class, IHandler where TMessage : class => AddHandler(services, ServiceLifetime.Transient, key); public static IServiceCollection AddHandler(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IHandler), key, typeof(THandler), lifetime)); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IHandler), typeof(THandler), lifetime)); services.AddInitialization>>(); } return services; } public static IServiceCollection AddHandler(this IServiceCollection services, string key) where THandler : class, IHandler where TMessage : class => AddHandler(services, ServiceLifetime.Transient, key); public static IServiceCollection AddHandler(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IHandler), key, typeof(THandler), lifetime)); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IHandler), typeof(THandler), lifetime)); services.AddInitialization>>(); } return services; } public static IServiceCollection AddScopedHandler(this IServiceCollection services, string key) where THandler : class, IHandler where TMessage : class => AddScopedHandler(services, ServiceLifetime.Transient, key); public static IServiceCollection AddScopedHandler(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IHandler where TMessage : class { if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IHandler), key, typeof(THandler), lifetime)); services.AddInitializationScoped>>(key); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IHandler), typeof(THandler), lifetime)); services.AddInitializationScoped>>(); services.AddInitialization>>(); } return services; } public static IServiceCollection AddScopedHandler(this IServiceCollection services, string key) where THandler : class, IHandler where TMessage : class => AddScopedHandler(services, ServiceLifetime.Transient, key); public static IServiceCollection AddScopedHandler(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient, string? key = null) where THandler : class, IHandler where TMessage : class { services.AddHandler(lifetime, key); if (key is { Length: > 0 }) { services.Add(new ServiceDescriptor(typeof(IHandler), key, typeof(THandler), lifetime)); services.AddInitializationScoped>>(key); services.AddInitialization>>(key); } else { services.Add(new ServiceDescriptor(typeof(IHandler), typeof(THandler), lifetime)); services.AddInitializationScoped>>(); services.AddInitialization>>(); } return services; } public static IServiceCollection AddInitialization(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient) where TInitialization : class, IInitialization where TInitializationImplementation : class, TInitialization { services.Add(new ServiceDescriptor(typeof(TInitialization), typeof(TInitializationImplementation), lifetime)); services.AddTransient(provider => provider.GetRequiredService()); return services; } public static IServiceCollection AddInitialization(this IServiceCollection services) where TInitialization : class, IInitialization { services.AddTransient(); return services; } public static IServiceCollection AddInitialization(this IServiceCollection services, params object[] parameters) where TInitialization : class, IInitialization { services.AddTransient(provider => provider.GetRequiredService() .Create(parameters)); return services; } public static IServiceCollection AddInitialization(this IServiceCollection services, Action delegateAction) { services.AddTransient(provider => new ActionableInitialization(provider, delegateAction)); return services; } public static IServiceCollection AddInitializationScoped(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Transient) where TInitialization : class, IInitialization where TInitializationImplementation : class, IInitializationScoped { services.Add(new ServiceDescriptor(typeof(IInitializationScoped), typeof(TInitializationImplementation), lifetime)); services.AddTransient(provider => provider.GetRequiredService()); return services; } public static IServiceCollection AddInitializationScoped(this IServiceCollection services) where TInitialization : class, IInitializationScoped { services.AddTransient(); return services; } public static IServiceCollection AddInitializationScoped(this IServiceCollection services, params object[] parameters) where TInitialization : class, IInitializationScoped { services.AddTransient(provider => provider.GetRequiredService() .Create(parameters)); return services; } public static IServiceCollection AddInitializationScoped(this IServiceCollection services, Action delegateAction) { services.AddTransient(provider => new ActionableInitializationScoped(provider, delegateAction)); return services; } public static IServiceCollection AddRange(this IServiceCollection services, IServiceCollection fromServices) { foreach (ServiceDescriptor service in fromServices) { services.Add(service); } return services; } public static IServiceCollection AddScopedService(this IServiceCollection services) where TScopedService : class { services.AddScoped, ScopedServiceDescriptor>(); services.AddScoped(provider => provider.GetRequiredService>().Value!); services.AddCache(); services.AddTransient, ScopedServiceProvider>(); services.AddTransient, ScopedServiceFactory>(); return services; } public static IServiceCollection AddScopedService(this IServiceCollection services, Action providerDelegate) where TScopedService : class { services.AddScoped, ScopedServiceDescriptor>(); services.AddScoped(provider => provider.GetRequiredService>().Value!); services.AddCache(); services.AddTransient, ScopedServiceProvider>(); services.AddTransient, ScopedServiceFactory>(provider => { providerDelegate.Invoke(provider); IServiceScopeFactory factory = provider.GetRequiredService(); ICache cache = provider.GetRequiredService>(); return new ScopedServiceFactory(factory, cache); }); return services; } public static IServiceCollection AddTemplate(this IServiceCollection services, object? key = null, ServiceLifetime serviceLifetime = ServiceLifetime.Transient, params object[]? parameters) { return AddTemplate(services, key, serviceLifetime, parameters); } public static IServiceCollection AddTemplate(this IServiceCollection services, object? key = null, ServiceLifetime serviceLifetime = ServiceLifetime.Transient, params object?[]? parameters) { Type viewModelType = typeof(TViewModel); Type viewModelImplementationType = typeof(TViewModelImplementation); Type viewType = typeof(TView); key ??= viewModelImplementationType.Name.Replace("ViewModel", ""); if (parameters is { Length: 0 }) { services.Add(new ServiceDescriptor(viewModelType, viewModelImplementationType, serviceLifetime)); } else { services.Add(new ServiceDescriptor(viewModelType, provider => provider.GetRequiredService().Create(parameters)!, serviceLifetime)); } services.Add(new ServiceDescriptor(viewType, viewType, serviceLifetime)); if (parameters is { Length: 0 }) { services.Add(new ServiceDescriptor(viewModelType, key, viewModelImplementationType, serviceLifetime)); } else { services.Add(new ServiceDescriptor(viewModelType, key, (provider, key) => provider.GetRequiredService().Create(parameters)!, serviceLifetime)); } services.Add(new ServiceDescriptor(viewType, key, viewType, serviceLifetime)); services.AddKeyedTransient(key, (provider, _) => new ContentTemplateDescriptor(key, viewModelImplementationType, viewType, parameters)); return services; } public static IServiceCollection AddValueTemplate(this IServiceCollection services, Func readDelegate, Action writeDelegate, object? key = null, ServiceLifetime serviceLifetime = ServiceLifetime.Transient, params object?[]? parameters) { parameters = [readDelegate, writeDelegate, .. parameters ?? Enumerable.Empty()]; return AddTemplate(services, key, serviceLifetime, parameters); } public static IServiceCollection AddValueTemplate(this IServiceCollection services, Func readDelegate, Action writeDelegate, object? key = null, ServiceLifetime serviceLifetime = ServiceLifetime.Transient, params object?[]? parameters) { parameters = [readDelegate, writeDelegate, .. parameters ?? Enumerable.Empty()]; return AddTemplate(services, key, serviceLifetime, parameters); } }