Inyección de Dependencias en ASP.NET Core: Servicios con parámetros

El registro de servicios con parámetros en Startup.cs es una técnica fundamental en ASP.NET Core que permite configurar servicios que requieren información específica para su inicialización. En este artículo, profundizaremos en este proceso y exploraremos cómo realizar este registro utilizando expresiones lambda en el contenedor de servicios de ASP.NET Core.

Uso de Expresiones Lambda para el Registro de Servicios

En ASP.NET Core, las expresiones lambda se utilizan para definir cómo se debe construir un servicio con parámetros específicos durante el registro en Startup.cs. Esto proporciona una flexibilidad considerable al permitir la configuración dinámica de los servicios en tiempo de ejecución.

Registro Básico de Servicios

Cuando se registra un servicio que no necesita parámetros específicos, el proceso es bastante directo:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // Registro de un servicio sin parámetros específicos
    services.AddTransient<IMyService, MyService>();
}

Registro de Servicios con Parámetros

Para servicios que necesitan parámetros específicos en su constructor, utilizamos expresiones lambda. Para registrar un servicio con un parámetro específico en Startup.cs, utilizamos una expresión lambda de la siguiente manera:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // Registro del servicio con un parámetro en el constructor utilizando una expresión lambda
    services.AddTransient<IMyService>(provider => 
    {
        // Definimos el parámetro necesario
        var parameter = "Mi Parámetro Especial";

        // Construimos y devolvemos la instancia del servicio con el parámetro proporcionado
        return new MyService(parameter);
    });
}

 

Registro de Servicios con Parámetros

Nota: El ejemplo de código que utilizaremos en este punto, está basado en el cliente de correo electrónico (SMTP) ASP.NET Core, que desarrollamos en el anterior artículo de este blog: Inyección de Dependencias en ASP.NET Core: Un cliente SMTP (I). Si quieres reproducir este ejemplo completo en Visual Studio, visita y lee con detenimiento los artículos:  Inyección de Dependencias en ASP.NET Core: Un cliente SMTP (I) y Inyección de Dependencias en ASP.NET Core: Un cliente SMTP (II).

Definir la Interfaz y la Implementación de un Servicio de Correo

Primero, vamos a definir una interfaz IMailService que describa el contrato del servicio de correo y luego implementar esta interfaz en una clase MailService.

public interface IMailService
{
    void SendEmail(string to, string subject, string body);
}

public class MailService : IMailService
{
    private readonly string _smtpServer;
    private readonly int _smtpPort;

    public MailService(string smtpServer, int smtpPort)
    {
        _smtpServer = smtpServer;
        _smtpPort = smtpPort;
    }

    public void SendEmail(string to, string subject, string body)
    {
        // Aquí iría la lógica para enviar el correo
        Console.WriteLine($"Enviando correo a {to} con asunto {subject} usando {_smtpServer}:{_smtpPort}");
    }
}

En esta implementación, MailService acepta parámetros para el servidor SMTP y el puerto en su constructor. Estos valores se almacenan en campos privados y se utilizan en el método SendEmail para enviar el correo electrónico.  Por simplicidad, estamos utilizando Console.WriteLine para simular el envío de correo.

Accede al archivo Startup.cs de tu proyecto ASP.NET Core. Agrega el Registro de Servicio dentro del método ConfigureServices, registra el servicio utilizando una expresión lambda para proporcionar los parámetros necesarios:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // Registro del servicio con parámetros en el constructor utilizando una expresión lambda
    services.AddTransient<IMailService>(provider => 
    {
        // Accede a la configuración de la aplicación para obtener los parámetros necesarios
        var smtpServer = Configuration["SmtpServer"];
        var smtpPort = int.Parse(Configuration["SmtpPort"]);

        // Construye y devuelve la instancia del servicio con los parámetros proporcionados
        return new MailService(smtpServer, smtpPort);
    });
}

Nota: En este ejemplo, estamos registrando IMailService con una implementación de MailService que requiere la dirección del servidor SMTP y el puerto como parámetros en su constructor. La expresión lambda ahora incluye la recuperación de estos parámetros de la configuración de la aplicación y la construcción de la instancia del servicio con ellos.

Uso del Parámetro "provider"

El parámetro provider es una instancia de IServiceProvider que permite acceder a otros servicios registrados en el contenedor. Esto es útil cuando se necesitan resolver dependencias adicionales durante la construcción del servicio registrado.

En este ejemplo, utilizaremos provider.GetRequiredService<IConfiguration>() para acceder al servicio de configuración y obtener la cadena de conexión para el servicio de base de datos. Supongamos que tenemos un servicio SomeOtherService que también necesita ser utilizado dentro de nuestra expresión lambda. Podemos acceder a este servicio utilizando el parámetro provider:

services.AddTransient<ISomeOtherService>(provider =>
{
    var config = provider.GetRequiredService<IConfiguration>();
    var connectionString = config.GetConnectionString("SomeConnectionString");

    return new SomeOtherService(connectionString);
});

Nota: En este ejemplo, estamos registrando ISomeOtherService con una implementación de SomeOtherService que también requiere una cadena de conexión, pero esta vez obtenida de la configuración de la aplicación. Utilizamos el parámetro provider para acceder al servicio de configuración y obtener la cadena de conexión necesaria para la inicialización de SomeOtherService.

 

Algunos ejemplos prácticos

Para comprender mejor cómo registrar servicios con parámetros en ASP.NET Core utilizando expresiones lambda, exploraremos tres ejemplos detallados que incluyen diferentes configuraciones de servicios en el archivo Startup.cs.

Ejemplo 1: Servicio de Almacenamiento de Datos con Logger

Supongamos que tenemos un servicio DataService que requiere una conexión a la base de datos y un logger en su constructor.

// Interfaz IDataService
public interface IDataService
{
    void SaveData(string data);
}

// Implementación de DataService
public class DataService : IDataService
{
    private readonly IDbConnection _dbConnection;
    private readonly ILogger<DataService> _logger;

    public DataService(IDbConnection dbConnection, ILogger<DataService> logger)
    {
        _dbConnection = dbConnection;
        _logger = logger;
    }

    public void SaveData(string data)
    {
        // Lógica para guardar los datos utilizando _dbConnection
        _logger.LogInformation($"Datos guardados en la base de datos: {data}");
    }
}

Para registrar este servicio en Startup.cs, utilizamos una expresión lambda:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // Registro del servicio con parámetros en el constructor utilizando una expresión lambda
    services.AddTransient<IDataService>(provider =>
    {
        var dbConnection = new SqlConnection("connectionString");
        var logger = provider.GetRequiredService<ILogger<DataService>>();

        return new DataService(dbConnection, logger);
    });
}
  • provider: Es una instancia de IServiceProvider que permite resolver otras dependencias registradas en el contenedor de servicios.
  • dbConnection: Parámetro necesario para la creación del DataService.
  • Expresión Lambda: Crea una nueva instancia de DataService con el dbConnection y el logger.

 

Ejemplo 2: Servicio de Notificación con Logger

Supongamos que NotificationService requiere un servicio de configuración y un logger en su constructor:

// Interfaz INotificationService
public interface INotificationService
{
    void Notify(string message);
}

// Implementación de NotificationService
public class NotificationService : INotificationService
{
    private readonly string _apiEndpoint;
    private readonly ILogger<NotificationService> _logger;

    public NotificationService(string apiEndpoint, ILogger<NotificationService> logger)
    {
        _apiEndpoint = apiEndpoint;
        _logger = logger;
    }

    public void Notify(string message)
    {
        _logger.LogInformation($"Notificación enviada a {_apiEndpoint}: {message}");
    }
}

Para registrar este servicio en Startup.cs, utilizamos una expresión lambda para obtener el logger del proveedor de servicios:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // Registro del servicio con parámetros en el constructor utilizando una expresión lambda
    services.AddTransient<INotificationService>(provider =>
    {
        var apiEndpoint = "https://api.notification.com";
        var logger = provider.GetRequiredService<ILogger<NotificationService>>();

        return new NotificationService(apiEndpoint, logger);
    });
}

 

  • provider.GetRequiredService<ILogger<NotificationService>>(): Resuelve el logger desde el contenedor de servicios.
  • apiEndpoint: Parámetro necesario para la creación del NotificationService.
  • Expresión Lambda: Crea una nueva instancia de NotificationService con el apiEndpoint y el logger.

 

Ejemplo 3: Servicio de Procesamiento de Pedidos con Dependencias Externas

Supongamos que tenemos un servicio OrderProcessingService que se encarga de procesar los pedidos de los clientes. Este servicio requiere una instancia de IOrderRepository para acceder a la base de datos de pedidos, un servicio de notificación INotificationService para informar al cliente sobre el estado del pedido, y un logger para registrar información sobre el proceso de procesamiento de pedidos.

// Interfaz IOrderProcessingService
public interface IOrderProcessingService
{
    Task ProcessOrderAsync(Order order);
}

// Implementación de OrderProcessingService
public class OrderProcessingService : IOrderProcessingService
{
    private readonly IOrderRepository _orderRepository;
    private readonly INotificationService _notificationService;
    private readonly ILogger<OrderProcessingService> _logger;

    public OrderProcessingService(IOrderRepository orderRepository, INotificationService notificationService, ILogger<OrderProcessingService> logger)
    {
        _orderRepository = orderRepository;
        _notificationService = notificationService;
        _logger = logger;
    }

    public async Task ProcessOrderAsync(Order order)
    {
        // Lógica para procesar el pedido y actualizar la base de datos
        await _orderRepository.SaveOrderAsync(order);

        // Envío de notificación al cliente sobre el estado del pedido
        _notificationService.SendNotification(order.CustomerEmail, $"Su pedido ({order.OrderId}) ha sido procesado exitosamente.");

        _logger.LogInformation($"Pedido ({order.OrderId}) procesado exitosamente
    }
}

Para registrar este servicio en Startup.cs y utilizarlo en la aplicación, utilizamos una expresión lambda para configurar las dependencias requeridas:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();

    // Registro del servicio con parámetros en el constructor utilizando una expresión lambda
    services.AddScoped<IOrderProcessingService>(provider =>
    {
        var orderRepository = provider.GetRequiredService<IOrderRepository>();
        var notificationService = provider.GetRequiredService<INotificationService>();
        var logger = provider.GetRequiredService<ILogger<OrderProcessingService>>();

        return new OrderProcessingService(orderRepository, notificationService, logger);
    });
}
  • provider.GetRequiredService<IOrderRepository>(): Resuelve la instancia de IOrderRepository desde el contenedor de servicios.
  • provider.GetRequiredService<INotificationService>(): Resuelve la instancia de INotificationService desde el contenedor de servicios.
  • provider.GetRequiredService<ILogger<OrderProcessingService>>(): Resuelve el logger desde el contenedor de servicios.
  • Expresión Lambda: Crea una nueva instancia de OrderProcessingService con las dependencias requeridas.

 

Conclusiones

En este artículo, hemos explorado detalladamente el proceso de registro de servicios con parámetros en ASP.NET Core. Hemos analizado cómo utilizar expresiones lambda para configurar dependencias personalizadas en el constructor de los servicios, lo que nos brinda una mayor flexibilidad en el desarrollo de nuestras aplicaciones.

Al comprender la importancia y el funcionamiento de las expresiones lambda en el registro de servicios, los desarrolladores pueden optimizar el flujo de trabajo de desarrollo y garantizar una mejor modularidad y mantenibilidad en sus proyectos ASP.NET Core.

A través de ejemplos prácticos, hemos demostrado cómo registrar servicios que requieren parámetros en su constructor. Estos ejemplos ilustran la utilidad y la versatilidad de utilizar expresiones lambda para el registro de servicios en ASP.NET Core.

 

  Compartir


  Nuevo comentario

El campo Comentario es obligatorio.
El campo Nombre es obligatorio.

  Comentarios

No hay comentarios para este Post.



Utilizamos cookies propias y de terceros para mejorar nuestros servicios y ofrecerle una mejor experiencia de navegación. Si continúa navegando consideramos que acepta su uso. Más información   Acepto