C# 无服务器函数:AWS Lambda — 从基础到高级水平
无服务器架构已牢固地融入现代开发世界。如果您已经掌握了在 C# 中创建 AWS Lambda 函数的基本语法,那么是时候进入下一个级别了。在本文中,我们将分析高级技术:依赖注入 (DI)、创建中间件、处理密钥以及异步模式。这些知识将帮助您为云解决方案编写更灵活、可测试且高性能的代码。
1. 在 AWS Lambda 中为 C# 进行依赖注入 (DI)
标准的 Lambda 函数模板通常会在每次调用时创建一个新的处理程序类实例。这会导致重复创建“重量级”对象(例如数据库客户端或 HTTP 客户端)。使用依赖注入容器 (DI) 可以解决这个问题,允许重用实例并管理其生命周期。
为了在 .NET 8+ 中为 Lambda 实现 DI,需要使用 Amazon.Lambda.AspNetCoreServer.Hosting 包。让我们看一个使用 IServiceCollection 配置 DI 的示例。
示例:在 Lambda 中配置 DI
using Amazon.Lambda.Core;using Amazon.Lambda.RuntimeSupport;using Amazon.Lambda.Serialization.SystemTextJson;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;
// 服务接口和实现public interface IWeatherService{ string GetForecast(string city);}
public class WeatherService : IWeatherService{ public string GetForecast(string city) => $"城市 {city} 的天气:+25°C,晴朗";}
// Lambda 处理程序public class Function{ private readonly IWeatherService _weatherService;
public Function() : this(Startup.CreateHostBuilder().Build()) { }
public Function(IHost host) { _weatherService = host.Services.GetRequiredService<IWeatherService>(); }
public async Task<string> FunctionHandler(string input, ILambdaContext context) { return _weatherService.GetForecast(input); }}
// 配置类public static class Startup{ public static IHostBuilder CreateHostBuilder() => Host.CreateDefaultBuilder() .ConfigureServices((context, services) => { services.AddSingleton<IWeatherService, WeatherService>(); // 在此处添加其他服务 });}重要提示: 对 AWS SDK 客户端(S3、DynamoDB)使用 AddSingleton,对轻量级服务使用 AddTransient。这可以减少“冷启动”时间并节省资源。
2. AWS Lambda 中的中间件:请求处理链
在 ASP.NET Core 中熟悉的中间件概念同样适用于 Lambda 函数。中间件允许添加横切逻辑:日志记录、错误处理、身份验证、响应压缩——而无需修改主要处理程序代码。
为了实现中间件,需要使用 Amazon.Lambda.AspNetCoreServer 包和 ILambdaMiddleware 接口(或自定义实现)。下面是一个创建简单中间件以记录执行时间的示例。
示例:用于日志记录的中间件
using Amazon.Lambda.Core;using System.Diagnostics;
public class LoggingMiddleware : ILambdaMiddleware{ public async Task<TResponse> InvokeAsync<TRequest, TResponse>(TRequest request, Func<TRequest, Task<TResponse>> next, ILambdaContext context) { var sw = Stopwatch.StartNew(); context.Logger.LogInformation($"收到请求:{request}");
try { var response = await next(request); sw.Stop(); context.Logger.LogInformation($"在 {sw.ElapsedMillis