Mile
Mile
CC#
Created by Mile on 10/2/2024 in #help
Managing Scoped Service Lifecycles with a Singleton Factory in .NET: Best Practices?
Hello everyone, I'm working on implementing a factory pattern for payment services in a .NET application and I'm unsure about properly managing the lifecycle of services. Here's the relevant part of my code:
public class ProviderServiceFactory
{
private readonly IServiceProvider _serviceProvider;
public ProviderServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IPaymentService CreateProviderService(ProviderDataDto providerDataDto)
{
var scoped = _serviceProvider.CreateScope();
var service = providerDataDto.IntegrationName switch
{
IntegrationName.PayPal => scoped.ServiceProvider.GetRequiredService<PayPalService>(),
IntegrationName.Stripe => scoped.ServiceProvider.GetRequiredService<StripeService>(),
_ => throw new ArgumentException("Invalid payment service type.")
};
service.Initialize(providerDataDto.CompanyMarketIntegrationKeyValues);
return service;
}
}
public class ProviderServiceFactory
{
private readonly IServiceProvider _serviceProvider;
public ProviderServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IPaymentService CreateProviderService(ProviderDataDto providerDataDto)
{
var scoped = _serviceProvider.CreateScope();
var service = providerDataDto.IntegrationName switch
{
IntegrationName.PayPal => scoped.ServiceProvider.GetRequiredService<PayPalService>(),
IntegrationName.Stripe => scoped.ServiceProvider.GetRequiredService<StripeService>(),
_ => throw new ArgumentException("Invalid payment service type.")
};
service.Initialize(providerDataDto.CompanyMarketIntegrationKeyValues);
return service;
}
}
And here's how I'm using it in a handler:
public async Task<Result<Uri>> Handle(AddPaymentMethodCommand command, CancellationToken cancellationToken)
{
// Validation and other logic..
Result<ProviderDataDto> providerDataResult = await _mediator.Send(new GetProviderDataQuery(command.CompanyMarketId, INTEGRATION_TYPE), cancellationToken);
if (!providerDataResult.IsSuccess)
{
return Result<Uri>.Failure(providerDataResult.Error);
}
IPaymentService paymentService = _providerServiceFactory.CreateProviderService(providerDataResult.Value);
// Create payment method, save to database...
Result<Uri> result = await paymentService.InitiatePaymentMethodTokenization(paymentMethod);
// Handle result...
}
public async Task<Result<Uri>> Handle(AddPaymentMethodCommand command, CancellationToken cancellationToken)
{
// Validation and other logic..
Result<ProviderDataDto> providerDataResult = await _mediator.Send(new GetProviderDataQuery(command.CompanyMarketId, INTEGRATION_TYPE), cancellationToken);
if (!providerDataResult.IsSuccess)
{
return Result<Uri>.Failure(providerDataResult.Error);
}
IPaymentService paymentService = _providerServiceFactory.CreateProviderService(providerDataResult.Value);
// Create payment method, save to database...
Result<Uri> result = await paymentService.InitiatePaymentMethodTokenization(paymentMethod);
// Handle result...
}
The ProviderServiceFactory is registered as a Singleton, while the payment services (like PayPalService) are registered as Scoped.
66 replies
CC#
Created by Mile on 8/23/2024 in #help
Payments - architectural dilemma
No description
7 replies