Funções Serverless em C#: AWS Lambda — do básico ao nível avançado
\n\nA arquitetura Serverless entrou firmemente no mundo do desenvolvimento moderno. Se você já domina a sintaxe básica de criação de funções AWS Lambda em C#, é hora de passar para o próximo nível. Neste artigo, abordaremos técnicas avançadas: injeção de dependência (DI), criação de Middleware, trabalho com segredos e padrões assíncronos. Esses conhecimentos ajudarão você a escrever código mais flexível, testável e eficiente para soluções em nuvem.
\n\n1. Injeção de dependência (DI) em AWS Lambda com C#
\n\nO modelo padrão de função Lambda frequentemente cria uma nova instância da classe manipuladora para cada chamada. Isso leva à recriação de objetos "pesados" (por exemplo, clientes de banco de dados ou clientes HTTP). O uso de um contêiner de injeção de dependência (DI) resolve esse problema, permitindo reutilizar instâncias e gerenciar seu tempo de vida.
\n\nPara implementar DI no .NET 8+ para Lambda, utiliza-se o pacote Amazon.Lambda.AspNetCoreServer.Hosting. Vejamos um exemplo de configuração de DI usando IServiceCollection.
Exemplo: Configuração de DI em 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// Interface e implementação do serviço\npublic interface IWeatherService\n{\n string GetForecast(string city);\n}\n\npublic class WeatherService : IWeatherService\n{\n public string GetForecast(string city) => $"Clima em {city}: +25°C, ensolarado";\n}\n\n// Manipulador 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// Classe de configuração\npublic static class Startup\n{\n public static IHostBuilder CreateHostBuilder() =>\n Host.CreateDefaultBuilder()\n .ConfigureServices((context, services) =>\n {\n services.AddSingleton<IWeatherService, WeatherService>();\n // Adicione outros serviços aqui\n });\n}\n\nImportante: Use AddSingleton para clientes AWS SDK (S3, DynamoDB) e AddTransient para serviços leves. Isso reduz o tempo de "cold start" e economiza recursos.
2. Middleware em AWS Lambda: cadeia de processamento de requisições
\n\nO conceito de Middleware, familiar do ASP.NET Core, também se aplica muito bem a funções Lambda. O Middleware permite adicionar lógica transversal: logging, tratamento de erros, autenticação, compressão de respostas — sem alterar o código principal do manipulador.
\n\nPara implementar Middleware, utiliza-se o pacote Amazon.Lambda.AspNetCoreServer e a interface ILambdaMiddleware (ou uma implementação personalizada). Abaixo está um exemplo de criação de um Middleware simples para logging de tempo de execução.
Exemplo: Middleware para logging
\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($"Requisição recebida: {request}");\n\n try\n {\n var response = await next(request);\n sw.Stop();\n context.Logger.LogInformation($"Resposta enviada em {sw.ElapsedMillis