Funciones Serverless en C#: AWS Lambda — de lo básico al nivel avanzado
\n\nLa arquitectura Serverless se ha consolidado en el mundo del desarrollo moderno. Si ya domina la sintaxis básica para crear funciones AWS Lambda en C#, es hora de pasar al siguiente nivel. En este artículo, analizaremos técnicas avanzadas: inyección de dependencias (DI), creación de Middleware, manejo de secretos y patrones asíncronos. Estos conocimientos le ayudarán a escribir código más flexible, comprobable y eficiente para soluciones en la nube.
\n\n1. Inyección de dependencias (DI) en AWS Lambda con C#
\n\nLa plantilla estándar de una función Lambda a menudo crea una nueva instancia de la clase controladora en cada invocación. Esto provoca la recreación de objetos "pesados" (como clientes de base de datos o clientes HTTP). El uso de un contenedor de inyección de dependencias (DI) resuelve este problema, permitiendo reutilizar instancias y gestionar su ciclo de vida.
\n\nPara implementar DI en .NET 8+ para Lambda, se utiliza el paquete Amazon.Lambda.AspNetCoreServer.Hosting. Veamos un ejemplo de configuración de DI usando IServiceCollection.
Ejemplo: Configuración de DI en Lambda
\n\nusing Amazon.Lambda.Core;\nusing Amazon.Lambda.RuntimeSupport;\nusing Amazon.Lambda.Serialization.SystemTextJson;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\n\n// Interfaz e implementación del servicio\npublic interface IWeatherService\n{\n string GetForecast(string city);\n}\n\npublic class WeatherService : IWeatherService\n{\n public string GetForecast(string city) => $"Clima en {city}: +25°C, soleado";\n}\n\n// Controlador Lambda\npublic class Function\n{\n private readonly IWeatherService _weatherService;\n\n public Function() : this(Startup.CreateHostBuilder().Build()) { }\n\n public Function(IHost host)\n {\n _weatherService = host.Services.GetRequiredService<IWeatherService>();\n }\n\n public async Task<string> FunctionHandler(string input, ILambdaContext context)\n {\n return _weatherService.GetForecast(input);\n }\n}\n\n// Clase de configuración\npublic static class Startup\n{\n public static IHostBuilder CreateHostBuilder() =>\n Host.CreateDefaultBuilder()\n .ConfigureServices((context, services) =>\n {\n services.AddSingleton<IWeatherService, WeatherService>();\n // Agregue otros servicios aquí\n });\n}\n\nImportante: Use AddSingleton para clientes de AWS SDK (S3, DynamoDB) y AddTransient para servicios ligeros. Esto reduce el tiempo de "arranque en frío" (cold start) y ahorra recursos.
2. Middleware en AWS Lambda: cadena de procesamiento de solicitudes
\n\nEl concepto de Middleware, conocido en ASP.NET Core, también se aplica perfectamente a las funciones Lambda. El Middleware permite agregar lógica transversal: registro, manejo de errores, autenticación, compresión de respuestas — sin modificar el código principal del controlador.
\n\nPara implementar Middleware se utiliza el paquete Amazon.Lambda.AspNetCoreServer y la interfaz ILambdaMiddleware (o una implementación personalizada). A continuación, se muestra un ejemplo de creación de un Middleware simple para registrar el tiempo de ejecución.
Ejemplo: Middleware para registro
\n\nusing Amazon.Lambda.Core;\nusing System.Diagnostics;\n\npublic class LoggingMiddleware : ILambdaMiddleware\n{\n public async Task<TResponse> InvokeAsync<TRequest, TResponse>(TRequest request, \n Func<TRequest, Task<TResponse>> next, ILambdaContext context)\n {\n var sw = Stopwatch.StartNew();\n context.Logger.LogInformation($"Solicitud recibida: {request}");\n\n try\n {\n var response = await next(request);\n sw.Stop();\n context.Logger.LogInformation($"Respuesta enviada en {sw.ElapsedMillis