Relay your dependency injection to the next level. Fluent extensions for Microsoft.Extensions.DependencyInjection that simplify adapter patterns with conditional routing, multi-adapters, adapter chains, and dynamic service resolution.
$ dotnet add package RelayRelay your dependency injection to the next level! A powerful, fluent library that extends Microsoft.Extensions.DependencyInjection with adaptive patterns for conditional routing, multi-relays, adapter chains, and dynamic service resolution.
By using this project or its source code, for any purpose and in any shape or form, you grant your implicit agreement to all of the following statements:
To learn more about the war and how you can help, click here. Glory to Ukraine! 🇺🇦
Transform the adapter pattern from a simple design pattern into a powerful architectural tool:
dotnet add package Relay
using Relay;
// Configure services
services.AddRelayServices();
// Basic relay
services.AddRelay<IPaymentService, StripePaymentRelay>()
.WithScopedLifetime();
// Conditional relay
services.AddConditionalRelay<IPaymentService>()
.When(ctx => ctx.Environment == "Development").RelayTo<MockPaymentService>()
.When(ctx => ctx.Environment == "Production").RelayTo<StripePaymentService>()
.Build();
// Multi-relay broadcasting
services.AddMultiRelay<INotificationService>(config => config
.AddRelay<EmailNotificationService>()
.AddRelay<SmsNotificationService>()
.WithStrategy(RelayStrategy.Broadcast)
).Build();
services.AddRelay<IPaymentService, StripePaymentRelay>()
.WithScopedLifetime()
.DecorateWith<LoggingDecorator>();
services.AddConditionalRelay<IPaymentService>()
.WithScopedLifetime()
.When(ctx => ctx.Environment == "Development")
.RelayTo<MockPaymentService>()
.When(ctx => ctx.Properties["PaymentMethod"].Equals("Stripe"))
.RelayTo<StripePaymentService>()
.When(ctx => ctx.Properties["PaymentMethod"].Equals("PayPal"))
.RelayTo<PayPalPaymentService>()
.Otherwise<DefaultPaymentService>()
.Build();
// Broadcast to all services
services.AddMultiRelay<INotificationService>(config => config
.AddRelay<EmailNotificationService>(ServiceLifetime.Singleton)
.AddRelay<SmsNotificationService>(ServiceLifetime.Scoped)
.AddRelay<PushNotificationService>(ServiceLifetime.Transient)
.WithStrategy(RelayStrategy.Broadcast)
).Build();
// Failover strategy
services.AddMultiRelay<IStorageService>(config => config
.AddRelay<PrimaryStorageService>()
.AddRelay<SecondaryStorageService>()
.AddRelay<BackupStorageService>()
.WithStrategy(RelayStrategy.Failover)
).Build();
// Your RefactoringGuru example becomes:
services.AddAdapter<ITarget, Adaptee>()
.WithScopedLifetime()
.Using<Adapter>();
// Legacy system integration
services.AddAdapter<IModernPaymentService, LegacyPaymentGateway>()
.WithScopedLifetime()
.WithAdapteeLifetime(ServiceLifetime.Singleton)
.Using<LegacyPaymentAdapter>();
// Factory-based adapters
services.AddAdapter<INotificationService, ThirdPartyEmailService>()
.Using(emailService => new EmailNotificationAdapter(emailService));
// Complex transformation pipeline
services.AddAdapterChain<IResult>()
.From<RawData>() // A (source)
.Then<ValidatedData, ValidationAdapter>() // A → B
.Then<EnrichedData, EnrichmentAdapter>() // B → C
.Finally<ProcessedResultAdapter>() // C → X (final)
.Build();
// Strongly-typed chain
services.AddTypedAdapterChain<XmlData, DomainModel>()
.Then<JsonData, XmlToJsonAdapter>()
.Then<DataDto, JsonToDtoAdapter>()
.Then<DomainModel, DtoToDomainAdapter>()
.Build();
services.AddRelayFactory<IPaymentService>(factory => factory
.RegisterRelay("stripe", provider => new StripeRelay())
.RegisterRelay("paypal", provider => new PayPalRelay())
.RegisterRelay("crypto", provider => new CryptoRelay())
.SetDefaultRelay("stripe")
).Build();
// Usage
var factory = serviceProvider.GetService<IRelayFactory<IPaymentService>>();
var paymentService = factory.CreateRelay("stripe");
services.AddRelay(config => config
.FromAssemblyOf<IPaymentService>()
.WithDefaultLifetime(ServiceLifetime.Scoped)
.RegisterRelays()
);
// Advanced discovery
services.AddAdaptersFromAssembly<IPaymentService>(ServiceLifetime.Scoped);
// Different lifetimes for different components
services.AddMultiRelay<INotificationService>(config => config
.WithDefaultLifetime(ServiceLifetime.Scoped)
.AddRelay<EmailService>(ServiceLifetime.Singleton) // Expensive to create
.AddRelay<SmsService>(ServiceLifetime.Scoped) // Request-specific
.AddRelay<PushService>(ServiceLifetime.Transient) // Independent operations
.WithStrategy(RelayStrategy.Broadcast)
).Build();
services.AddConditionalAdapterChain<IUserService>()
.When(ctx => ctx.Environment == "Development")
.UseChain(chain => chain
.From<MockDatabase>()
.Finally<MockUserService>())
.When(ctx => ctx.Environment == "Production")
.UseChain(chain => chain
.From<LegacyDatabase>()
.Then<IModernOrm, LegacyToOrmAdapter>()
.Then<IRepository<User>, OrmToRepositoryAdapter<User>>()
.Finally<RepositoryToServiceAdapter>())
.Build();
services.AddParallelAdapterChains<IDataProcessor>()
.AddChain("fast", chain => chain
.From<RawData>()
.Then<CachedData, FastCacheAdapter>()
.Finally<FastProcessorAdapter>())
.AddChain("thorough", chain => chain
.From<RawData>()
.Then<ValidatedData, ValidationAdapter>()
.Then<EnrichedData, EnrichmentAdapter>()
.Finally<ThoroughProcessorAdapter>())
.Build();
// Usage
var chainFactory = serviceProvider.GetService<IAdapterChainFactory<IDataProcessor>>();
var processor = chainFactory.CreateFromChain("thorough");
// Easy mocking for tests
services.AddConditionalRelay<IPaymentService>()
.When(ctx => ctx.Properties["TestMode"].Equals("Mock"))
.RelayTo<MockPaymentService>()
.When(ctx => ctx.Properties["TestMode"].Equals("Integration"))
.RelayTo<TestPaymentService>()
.Build();
# Package Manager
Install-Package Relay
# .NET CLI
dotnet add package Relay
# PackageReference
<PackageReference Include="Relay" Version="1.0.0" />
using Relay;
public void ConfigureServices(IServiceCollection services)
{
// Add relay services
services.AddRelayServices();
// Configure your relays
services.AddRelay(config => config
.FromAssemblyOf<IPaymentService>()
.RegisterRelays()
);
}
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
This project is licensed under the MIT License - see the LICENSE file for details.
If you find this project helpful, please consider:
Relay transforms dependency injection from simple service registration into a powerful architectural pattern for building maintainable, scalable .NET applications! 🚀