.NET Conf 2023 – Celebrating the Release of .NET 8! – Save the Date!
Esta funcionalidad ya estaba presente en otros frameworks de DI en .NET, como es Autofac, pero los que me conocen saben que soy poco partidario de meter librerías de terceros, excepto que sea imposible hacer uso de algo estándar del lenguaje y el tiempo del proyecto no permita que nuestro equipo lo construya a partir del estándar. Dicho esto, es una buena noticia ver esta funcionalidad. Veamos por qué:
Los servicios con clave (keyed services) son una forma de almacenar información adicional con el ServiceDescriptor. Esta información adicional es una ServiceKey, que sirve para identificar el servicio. Esta clave puede ser cualquier objeto, aunque normalmente es una cadena de texto o un valor constante. En los servicios sin clave, el tipo de servicio (ServiceType) es lo que permite identificar el registro del servicio. Pero en los servicios con clave, es la combinación del tipo de servicio y la clave lo que permite esta identificación.
Un ejemplo:
Los servicios con clave son útiles cuando tienes una interfaz/servicio con múltiples implementaciones que deseas usar en tu aplicación. Además, necesitas usar cada una de esas implementaciones en diferentes lugares de tu aplicación.
Como ejemplo, considera la siguiente interfaz e implementación:
public interface IPaymentService
{
string Payment(string type);
}
public class PaypalPaymentService : IPaymentService
{
public string Payment(string type) => $"[Paypal]";
}
public class CreditCartPaymentService : IPaymentService
{
public string Payment(string type) => $"[CreditCart]";
}
public class TrasnferPaymentService : IPaymentService
{
public string Payment(string type) => $"[Trasnfer]";
}
Su uso sin keyed Services:
// Registar todos los servicios
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IPaymentService, PaypalPaymentService>();
builder.Services.AddSingleton<IPaymentService, CreditCartPaymentService>();
builder.Services.AddSingleton<IPaymentService, TrasnferPaymentService>();
// Obtener todos los servicios
public class PaymentService(IEnumerable<IPaymentService> services)
{
//Tu código
}
// Si haces esto solo obtienes el último servicio registrado
public class PaymentService(IPaymentService service)
{
//Tu código
}
No esiste una forma sencilla de recuperar los servicios, casi siempre he utilizado este pequeño truco: registrar el servicio como un tipo concreto y delegar el registro de IPaymentService.
Pero ahora es más sencillo, usando keyed services:
// Registar todos los servicios
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IPaymentService, PaypalPaymentService>("paypal");
builder.Services.AddSingleton<IPaymentService, CreditCartPaymentService>("creditcard");
builder.Services.AddSingleton<IPaymentService, TrasnferPaymentService>("trasnfer");
// Uso
class PaypalPaymentService([FromKeyedServices("paypal")] IPaymentService paymentServices)
{
//Tu código
}
class CreditCartPaymentService(IKeyedServiceProvider keyedServiceProvider)
{
var paymentService = keyedServiceProvider.GetRequiredKeyedService<IPayentService>("creditcard");
//Tu código
}