Amazon.Lambda.Annotations 1.5.0

前缀已预留
dotnet add package Amazon.Lambda.Annotations --version 1.5.0                
NuGet\Install-Package Amazon.Lambda.Annotations -Version 1.5.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Amazon.Lambda.Annotations" Version="1.5.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Amazon.Lambda.Annotations --version 1.5.0                
#r "nuget: Amazon.Lambda.Annotations, 1.5.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Amazon.Lambda.Annotations as a Cake Addin
#addin nuget:?package=Amazon.Lambda.Annotations&version=1.5.0

// Install Amazon.Lambda.Annotations as a Cake Tool
#tool nuget:?package=Amazon.Lambda.Annotations&version=1.5.0                

Amazon.Lambda.Annotations

Lambda Annotations 是一种用于编写 .NET Lambda 函数的编程模型。这个编程模型允许使用传统的 .NET 编码模式。使用 C# 源生成器 将 Lambda 编程模型与 Lambda Annotations 编程模型相连接,而不增加任何性能开销。

主题

Lambda Annotations 如何工作?

.NET Lambda函数的默认编写体验是编写一个接受事件对象的.NET方法。从这里开始,编写样板代码来解析事件对象中的数据,并同步CloudFormation模板以定义Lambda函数和每个事件要调用的.NET方法。以下是一个使用默认Lambda编程模型的简单示例,该示例像一个计算器加法方法。它响应API Gateway REST API,从资源路径提取操作数,执行加法并返回API Gateway响应。

public class Functions
{
    public APIGatewayProxyResponse LambdaMathPlus(APIGatewayProxyRequest request, ILambdaContext context)
    {
        if (!request.PathParameters.TryGetValue("x", out var xs))
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };
        }
        if (!request.PathParameters.TryGetValue("y", out var ys))
        {
            return new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.BadRequest
            };
        }

        var x = int.Parse(xs);
        var y = int.Parse(ys);

        return new APIGatewayProxyResponse
        {
            StatusCode = (int)HttpStatusCode.OK,
            Body = (x + y).ToString(),
            Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
        };
    } 
}

使用Lambda注解,相同的Lambda函数可以删除大部分样板代码,并像这样编写方法。

public class Functions
{
    [LambdaFunction]
    [RestApi("/plus/{x}/{y}")]
    public int Plus(int x, int y)
    {
        return x + y;
    }
}

Lambda注解使用C#源生成器在编译时生成该样板代码,在默认Lambda编程模型和Lambda注解编程模型之间架设桥梁。此外,源生成器还会同步CloudFormation模板,将具有LambdaFunction属性的.NET方法声明为CloudFormation模板中的Lambda函数。

入门指南

要开始使用Lambda注解,有一个Lambda蓝图可用。对于Visual Studio用户,可以通过AWS Toolkit for Visual Studio访问蓝图。对于非Visual Studio用户,可以使用Amazon.Lambda.Templates NuGet包创建.NET Lambda项目。

Visual Studio 2022

要开始使用Visual Studio,请安装AWS Toolkit for Visual Studio扩展。安装后,可以通过以下步骤创建一个预配置的Lambda注解项目

  • 选择创建新项目
  • 在模板搜索框中输入AWS Serverless
  • 从搜索结果中,选择AWS Serverless Application (.NET Core C#)并点击下一步
  • 命名项目并点击创建
  • 将显示选择蓝图向导,用于选择项目的初始内容。
  • 选择Annotations Framework蓝图并点击完成

.NET CLI

可以使用.NET CLI的dotnet new命令创建.NET Lambda项目。要使用Lambda注解库创建一个项目,请在终端运行以下步骤。

  • 运行dotnet new install Amazon.Lambda.Templates将AWS Lambda模板安装到.NET CLI
  • 运行dotnet new serverless.Annotations --output FirstAnnotationsProject以使用Lambda Annotations创建项目

这将在一个名为FirstAnnotationsProject的子目录中创建一个项目。该目录将包含使用注释的Lambda项目和单元测试项目。

示例项目

示例项目包含以下文件

  • Functions.cs - 使用Lambda Annotation定义一组REST API Lambda函数。
  • Startup.cs - 在这里注册服务以将依赖关系注入Lambda函数。
  • serverless.template - 使用的CloudFormation模板来部署Lambda函数。Lambda Annotations库将自动同步CloudFormation模板中定义的项目中的函数。
  • aws-lambda-tools-defaults.json - 用来部署的默认设置的配置文件。

要重置为空项目,请删除Functions类中的代码并重新编译项目。Lambda Annotations库将从CloudFormation模板中删除所有Lambda函数声明。如果项目不包含使用API Gateway的HTTP API事件源的Lambda函数,则应手动从CloudFormation模板中删除ApiURL输出参数。

部署

Lambda Annotations 库的部署无需特殊工具。任何支持基于 CloudFormation 的 .NET Lambda 函数部署的工具都与 Lambda Annotations 兼容。这包括AWS Toolkit for Visual StudioAmazon.Lambda.Tools (.NET CLI 的全局工具,可以使用命令 dotnet tool install --global Amazon.Lambda.Tools 安装) 以及 AWS SAM CLI

对于 AWS Toolkit for Visual Studio 的部署,可以在“解决方案资源管理器”中右击 Lambda 项目,然后选择 发布到 AWS Lambda...。这将启动一个向导,用于配置 CloudFormation 堆栈的名称和存储编译后的 Lambda 函数部署包的 S3 存储桶。

Amazon.Lambda.Tools 是一个用于 .NET CLI 的全局工具,可以使用以下命令安装:dotnet tool install --global Amazon.Lambda.Tools。安装完成后,可以在 Lambda 项目的目录中运行 dotnet lambda deploy-serverless 命令来启动部署。

将 Lambda Annotations 添加到现有项目

可以在现有项目中添加 Lambda Annotations。Lambda Annotations 需要使用 CloudFormation 模板部署现有项目。未来 Lambda Annotations 可能会支持其他部署技术。

要在现有项目中开始使用 Lambda Annotations,请将 Amazon.Lambda.Annotations NuGet 包添加为引用。然后使用 LambdaFunction 属性装饰应该作为 Lambda 函数公开的 C# 方法。如果将 LambdaFunction 属性添加到已在 CloudFormation 模板中声明的已声明方法中,则应手动删除原始声明。

依赖注入集成

Lambda Annotations 支持依赖注入。可以给一个类添加 LambdaStartup 属性。该类将有一个用于配置服务的 ConfigureServices 方法。

服务可以通过构造函数注入或在带有 LambdaFunction 属性的装饰函数的方法参数上使用 FromServices 属性进行注入。

通过构造函数注入的服务具有与 Lambda 计算容器的生命周期相同的生命周期。对于每个 Lambda 调用都会创建一个范围,并在此范围内创建使用 FromServices 属性注入的服务。

示例启动类

[LambdaStartup]
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAWSService<Amazon.S3.IAmazonS3>();
        services.AddScoped<ITracker, DefaultTracker>();
    }
}

使用依赖注入的示例函数

public class Functions
{
    IAmazonS3 _s3Client;

    public Functions(IAmazonS3 s3Client)
    {
        _s3Client = s3Client;
    }


    [LambdaFunction]
    [HttpApi(LambdaHttpMethod.Put, "/process/{name}")]
    public async Task Process([FromServices] ITracker tracker, string name, [FromBody] string data)
    {
        tracker.Record();

        await _s3Client.PutObjectAsync(new PutObjectRequest
        {
            BucketName = "storage-bucket",
            Key = name,
            ContentBody = data
        });
    }
}

同步 CloudFormation 模板

当 .NET 项目编译时,Lambda Annotation 源生成器将同步项目中所有带有 LambdaFunction 属性的 C# 方法与 CloudFormation 模板中的方法。支持基于 JSON 和 YAML 的 CloudFormation 模板。源生成器通过查看 aws-lambda-tools-defaults.json 文件中的 template 属性来识别项目的 CloudFormation 模板。如果不存在 template 属性,源生成器将默认使用 serverless.template 并生成文件(如果不存在)。

源生成器同步 CloudFormation 模板中的 Lambda 资源。该模板仍然可以编辑以添加其他 AWS 资源或进一步自定义 Lambda 函数,例如添加其他 Lambda Annotations 属性不支持的事件源。

当 .NET 方法同步到 CloudFormation 模板时,源生成器将添加以下所示的 Tool 元数据属性。此元数据将 CloudFormation 资源链接到源生成器。如果从 C# 方法中删除了 LambdaFunction 属性,则源生成器将删除 CloudFormation 资源。要解除 CloudFormation 资源与源生成器之间的链接,请删除 Tool 元数据属性。


  ...

"CloudCalculatorFunctionsAddGenerated": {
    "Type": "AWS::Serverless::Function",
    "Metadata": {
        "Tool": "Amazon.Lambda.Annotations",
        "SyncedEvents": [
            "RootGet"
        ]
    },
    "Properties": {
    "Runtime": "dotnet6",
    "CodeUri": ".",

  ...
}

LambdaFunction 属性包含映射到 CloudFormation 资源属性的属性。例如,在这个代码片段中,Lambda 函数的 MemorySizeTimeout 属性在 C# 代码中设置。源生成器将同步这些属性到 CloudFormation 模板中。

[LambdaFunction(MemorySize = 512, Timeout = 55)]
[HttpApi(LambdaHttpMethod.Get, "/add/{x}/{y}")]
public int Add(int x, int y, ILambdaContext context)
{
    context.Logger.LogInformation($"{x} plus {y} is {x + y}");
    return x + y;
}

一些 CloudFormation 属性没有设置为特定的值,而是引用 CloudFormation 模板中定义的另一个资源或参数。要在 .NET 属性的属性值中表示要引用另一个 CloudFormation 资源,请用 @ 前缀值。以下是一个示例,Lambda 函数的 Role 用于引用在 CloudFormation 模板中定义为 LambdaRoleParameter 的 IAM 角色。

public class Functions
{
    [LambdaFunction( Role="@LambdaRoleParameter")]
    [RestApi("/plus/{x}/{y}")]
    public int Plus(int x, int y)
    {
        return x + y;
    }
}
    "CloudCalculatorFunctionsAddGenerated": {
      "Type": "AWS::Serverless::Function",
      "Metadata": {
        "Tool": "Amazon.Lambda.Annotations",
        "SyncedEvents": [
          "RootGet"
        ]
      },
      "Properties": {
        "Runtime": "dotnet6",

...
        "Role": {
          "Fn::GetAtt": [
            "LambdaRoleParameter",
            "Arn"
          ]
        }
      }
    },

默认情况下,Lambda 标注将更新 CloudFormation 模板的 描述字段,包括用于修改模板的 Lambda 标注的版本。

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Transform": "AWS::Serverless-2016-10-31",
  "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v0.9.0.0).",
   ...

这个描述允许 AWS 记录 Lambda 标注框架的版本和用法,以便提高其质量。我们在 CloudFormation 堆栈级别记录详细信息,不识别部署的应用程序、库或工具。请注意,我们不记录任何个人信息,例如用户名、电子邮件地址或敏感的项目级信息。

如果您不希望 AWS 跟踪库的用法,请在您的项目(csproj)文件中设置以下内容:

<PropertyGroup>
  <AWSSuppressLambdaAnnotationsTelemetry>true</AWSSuppressLambdaAnnotationsTelemetry>
</PropertyGroup>

Lambda 全局属性

有一个 LambdaGlobalProperties 属性可以设置全局设置,当在编译时生成代码时,这个标注框架会使用这些设置。这简化了使用自定义运行时或本地提前(AOT)编译时的编程模型。它消除了手动引导 Lambda 运行时所需的过程。

要自动生成 static Main 方法,首先确保在您的 csproj 文件中将 OutputType 设置为 exe

<PropertyGroup>
    
    <OutputType>exe</OutputType>
</PropertyGroup>

一旦输出类型设置为可执行文件,添加 LambdaGlobalProperties 程序集属性,并将 GenerateMain 属性设置为 true。如果全局属性中未指定 Runtime,Lambda 注解将尝试从您的项目文件中确定它。您还可以在生成的 CloudFormation 模板中配置 Runtime

为了允许在同一个可执行文件中有多个 Lambda 函数,使用环境变量来确定要执行哪个处理器。当使用 GenerateMain 属性时,请确保部署的 Lambda 函数上设置 ANNOTATIONS_HANDLER 环境变量。

自动生成的 CloudFormation 模板将此作为默认值包括在内。

Amazon API Gateway 例子

此示例通过 Amazon API Gateway 创建了一个 REST API,该 API 公开了通用的算术运算。

为了避免将业务逻辑放在 REST API 中,创建了一个单独的计算服务来封装算术运算的逻辑。以下是计算服务的接口和默认实现。

public interface ICalculatorService
{
    int Add(int x, int y);

    int Subtract(int x, int y);

    int Multiply(int x, int y);

    int Divide(int x, int y);
}

public class DefaultCalculatorService : ICalculatorService
{
    public int Add(int x, int y) => x + y;

    public int Subtract(int x, int y) => x - y;

    public int Multiply(int x, int y) => x * y;

    public int Divide(int x, int y) => x / y;
}

启动类包含表示它为配置依赖注入框架中注册的服务类的 LambdaStartup 属性。在这里,ICalculatorService 被注册为服务集合中的单例服务。

[LambdaStartup]
public class Startup
{

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<ICalculatorService, DefaultCalculatorService>();
    }
}

由于 ICalculatorService 被注册为单例,因此服务通过构造函数注入到 Lambda 函数中。如果注册的服务被注册为作用域或瞬时的,并且每个 Lambda 调用都需要一个新的实例,则应在 Lambda 函数的方法参数上使用 FromServices 属性。

public class Functions
{
    ICalculatorService _calculatorService;
    public Functions(ICalculatorService calculatorService)
    {
        _calculatorService = calculatorService;
    }

    ...

对于每个算术运算,添加一个包含 LambdaFunction 属性的单独的 C# 方法。LambdaFunction 属性确保依赖注入框架连接到 Lambda 函数,Lambda 函数也将声明在 CloudFormation 模板中。

由于这些Lambda函数响应API网关事件,因此添加了HttpApi属性以在CloudFormation中注册事件源,包括HTTP动词和资源路径。此外,HttpApi属性还允许将HTTP请求组件映射到方法参数。在这种情况下,用于算术运算的操作数是从资源路径映射过来的。请在参考部分查看Lambda属性的列表,了解如何将HTTP请求的其他组件映射到方法参数。

[LambdaFunction()]
[HttpApi(LambdaHttpMethod.Get, "/add/{x}/{y}")]
public int Add(int x, int y, ILambdaContext context)
{
    context.Logger.LogInformation($"{x} plus {y} is {x + y}");
    return _calculatorService.Add(x, y);
}

[LambdaFunction()]
[HttpApi(LambdaHttpMethod.Get, "/subtract/{x}/{y}")]
public int Subtract(int x, int y, ILambdaContext context)
{
    context.Logger.LogInformation($"{x} subtract {y} is {x - y}");
    return _calculatorService.Subtract(x, y);
}

[LambdaFunction()]
[HttpApi(LambdaHttpMethod.Get, "/multiply/{x}/{y}")]
public int Multiply(int x, int y, ILambdaContext context)
{
    context.Logger.LogInformation($"{x} multiply {y} is {x * y}");
    return _calculatorService.Multiply(x, y);
}

[LambdaFunction()]
[HttpApi(LambdaHttpMethod.Get, "/divide/{x}/{y}")]
public int Divide(int x, int y, ILambdaContext context)
{
    context.Logger.LogInformation($"{x} divide {y} is {x / y}");
    return _calculatorService.Divide(x, y);
}

对于每个声明的LambdaFunction,源生成器将更新CloudFormation模板,添加相应的资源。Lambda CloudFormation资源将设置Handler属性为通过Lambda注解生成的的方法。这个生成的方法就是Lambda注解与Lambda编程模型之间连接的桥梁。HttpApi属性还添加了API网关事件源。

    "CloudCalculatorFunctionsAddGenerated": {
      "Type": "AWS::Serverless::Function",
      "Metadata": {
        "Tool": "Amazon.Lambda.Annotations",
        "SyncedEvents": [
          "RootGet"
        ]
      },
      "Properties": {
        "Runtime": "dotnet6",
        "CodeUri": ".",
        "MemorySize": 256,
        "Timeout": 30,
        "PackageType": "Zip",
        "Handler": "CloudCalculator::CloudCalculator.Functions_Add_Generated::Add",
        "Events": {
          "RootGet": {
            "Type": "HttpApi",
            "Properties": {
              "Path": "/add/{x}/{y}",
              "Method": "GET",
              "PayloadFormatVersion": "2.0"
            }
          }
        }
      }
    },

下面是源生成器为Add Lambda功能生成的代码示例。生成的代码包装了一个具有LambdaFunction属性的C#方法。它负责配置依赖注入、从API网关事件中获取参数并调用包装的LambdaFunction。这段代码仅用于参考,作为Lambda注解框架的用户,不需要查看此代码。

public class Functions_Add_Generated
{
    private readonly ServiceProvider serviceProvider;

    public Functions_Add_Generated()
    {
        var services = new ServiceCollection();

        // By default, Lambda function class is added to the service container using the singleton lifetime
        // To use a different lifetime, specify the lifetime in Startup.ConfigureServices(IServiceCollection) method.
        services.AddSingleton<Functions>();

        var startup = new CloudCalculator.Startup();
        startup.ConfigureServices(services);
        serviceProvider = services.BuildServiceProvider();
    }

    public Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse Add(Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest request, Amazon.Lambda.Core.ILambdaContext context)
    {
        // Create a scope for every request,
        // this allows creating scoped dependencies without creating a scope manually.
        using var scope = serviceProvider.CreateScope();
        var functions = scope.ServiceProvider.GetRequiredService<Functions>();

        var validationErrors = new List<string>();

        var x = default(int);
        if (request.PathParameters?.ContainsKey("x") == true)
        {
            try
            {
                x = (int)Convert.ChangeType(request.PathParameters["x"], typeof(int));
            }
            catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException)
            {
                validationErrors.Add($"Value {request.PathParameters["x"]} at 'x' failed to satisfy constraint: {e.Message}");
            }
        }

        var y = default(int);
        if (request.PathParameters?.ContainsKey("y") == true)
        {
            try
            {
                y = (int)Convert.ChangeType(request.PathParameters["y"], typeof(int));
            }
            catch (Exception e) when (e is InvalidCastException || e is FormatException || e is OverflowException || e is ArgumentException)
            {
                validationErrors.Add($"Value {request.PathParameters["y"]} at 'y' failed to satisfy constraint: {e.Message}");
            }
        }

        // return 400 Bad Request if there exists a validation error
        if (validationErrors.Any())
        {
            return new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse
            {
                Body = @$"{{""message"": ""{validationErrors.Count} validation error(s) detected: {string.Join(",", validationErrors)}""}}",
                Headers = new Dictionary<string, string>
                {
                    {"Content-Type", "application/json"},
                    {"x-amzn-ErrorType", "ValidationException"}
                },
                StatusCode = 400
            };
        }

        var response = functions.Add(x, y, context);

        var body = response.ToString();

        return new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse
        {
            Body = body,
            Headers = new Dictionary<string, string>
            {
                {"Content-Type", "application/json"}
            },
            StatusCode = 200
        };
    }
}

Amazon S3 例子

未使用API网关的Lambda函数可以利用Lambda注解的依赖注入集成和CloudFormation同步功能。以下是一个响应S3事件并调整上传到S3的图片大小的Lambda函数示例。

Startup类用于注册函数所需的服务。在示例中注册了两个服务。首先,是AWS SDK的S3客户端。第二个是处理图片处理的IImageServices。在示例中,将IImageService注册为一个transient服务,这样我们可以在每次调用时创建一个新的实例。这通常在有状态的服务中是必须的,这些状态不应该在每次调用之间保持。

[LambdaStartup]
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Using the AWSSDK.Extensions.NETCore.Setup package add the AWS SDK's S3 client
        services.AddAWSService<Amazon.S3.IAmazonS3>();

        // Add service for handling image manipulation. 
        // IImageServices is added as transient service so a new instance
        // is created for each Lambda invocation. This can be important if services
        // have state that should not be persisted per invocation.
        services.AddTransient<IImageServices, DefaultImageServices>();
    }
}

在Lambda函数中,通过依赖注入框架通过构造函数注入AWS SDK的S3客户端。构造函数在每次Lambda调用时只被调用一次,因此对于已注册为transient的IImageServices,通过构造函数注入该服务是没有意义的。相反,使用FromServices属性将IImageServices作为方法参数注入,确保每次调用方法时都会创建一个新的IImageServices实例。

Resize方法上,通过LambdaFunction属性设置Lambda功能的MemorySizeTimeout属性。源生成器将同步这些值到CloudFormation模板中对应的属性。同样设置Role属性,但是在这个例子中,值前面加了一个@符号。这个@告诉源生成器将角色值视为对CloudFormation模板中另一个元素的引用。在这个例子中,CloudFormation模板定义了一个名为LambdaResizeImageRole的IAM角色,Lambda函数应使用该IAM角色。

public class Functions
{
    private IAmazonS3 _s3Client;

    public Functions(IAmazonS3 s3Client)
    {
        _s3Client = s3Client;
    }

    [LambdaFunction(MemorySize = 1024, Timeout = 120, Role = "@LambdaResizeImageRole")]
    public async Task Resize([FromServices] IImageServices imageServices, S3Event evnt, ILambdaContext context)
    {
        var transferUtility = new TransferUtility(this._s3Client);

        foreach(var record in evnt.Records)
        {
            var tempFile = Path.GetTempFileName();

            // Download image from S3
            await transferUtility.DownloadAsync(tempFile, record.S3.Bucket.Name, record.S3.Object.Key);

            // Resize the image
            var resizeImagePath = await imageServices.ResizeImageAsync(imagePath: tempFile, width: 50, height: 50);

            // Upload resized image to S3 with a "/thumbnails" prefix in the object key.
            await transferUtility.UploadAsync(resizeImagePath, record.S3.Bucket.Name, "/thumbnails" + record.S3.Object.Key);
        }
    }
}

源生成器将在CloudFormation模板中创建Lambda函数资源。源生成器将同步通过LambdaFunction属性定义的属性。模板中同步的Lambda函数资源也可以在模板中进行直接修改。在这个示例中,函数被修改以定义事件源,在这种情况下是S3。

    "ImageResizerFunctionFunctionsResizeGenerated": {
      "Type": "AWS::Serverless::Function",
      "Metadata": {
        "Tool": "Amazon.Lambda.Annotations"
      },
      "Properties": {
        "Runtime": "dotnet6",
        "CodeUri": ".",
        "MemorySize": 1024,
        "Timeout": 120,
        "PackageType": "Zip",
        "Handler": "ImageResizerFunction::ImageResizerFunction.Functions_Resize_Generated::Resize",
        "Role": {
          "Fn::GetAtt": [
            "LambdaResizeImageRole",
            "Arn"
          ]
        },
        "Events": {
          "S3Objects": {
            "Type": "S3",
            "Properties": {
              "Bucket": {
                "Ref": "ImageBucket"
              },
              "Filter": {
                "S3Key": {
                  "Rules": [
                    {
                      "Name": "prefix",
                      "Value": "/images"
                    }
                  ]
                }
              },
              "Events": [
                "s3:ObjectCreated:*"
              ]
            }
          }
        }
      }
    },

以下是源生成器将为该函数生成的代码。构造函数用于处理依赖注入的设置。在生成的Resize方法中创建了一个依赖注入范围,然后从依赖注入中检索IImageServices并将其传递到开发者编写的函数。通过在生成的Resize方法中创建范围,所有注册为作用域或瞬时的服务在从依赖注入框架中检索时都将触发创建新实例。此代码片段仅用于信息目的,作为Lambda Annotations框架的用户,此代码不应需要查看。

public class Functions_Resize_Generated
{
    private readonly ServiceProvider serviceProvider;

    public Functions_Resize_Generated()
    {
        var services = new ServiceCollection();

        // By default, Lambda function class is added to the service container using the singleton lifetime
        // To use a different lifetime, specify the lifetime in Startup.ConfigureServices(IServiceCollection) method.
        services.AddSingleton<Functions>();

        var startup = new ImageResizerFunction.Startup();
        startup.ConfigureServices(services);
        serviceProvider = services.BuildServiceProvider();
    }

    public async System.Threading.Tasks.Task Resize(Amazon.Lambda.S3Events.S3Event evnt, Amazon.Lambda.Core.ILambdaContext __context__)
    {
        // Create a scope for every request,
        // this allows creating scoped dependencies without creating a scope manually.
        using var scope = serviceProvider.CreateScope();
        var functions = scope.ServiceProvider.GetRequiredService<Functions>();

        var imageServices = scope.ServiceProvider.GetRequiredService<ImageResizerFunction.IImageServices>();
        await functions.Resize(imageServices, evnt, __context__);
    }
}

SQS 事件例子

本例展示了用户如何使用SQSEvent属性来设置他们的SQS队列与Lambda函数之间的事件源映射。

SQSEvent属性包含以下属性

  • 队列(必需)- 将作为Lambda函数的事件触发器的SQS队列。这可以是队列ARN或引用服务器端无服务器模板中已定义的SQS队列资源。要在服务器端无服务器模板中引用SQS队列资源,请在资源名称前加“@”符号。
  • ResourceName(可选)- SQS事件源映射的CloudFormation资源名称。默认情况下,如果Queue设置为SQS队列ARN,则将其设置为SQS队列名称。如果Queue设置为现有CloudFormation资源,则使用该资源名称作为默认值,而不加“@”前缀。
  • Enabled(可选)- 如果设置为false,则事件源映射将被禁用,并且消息轮询将暂停。默认值为true。
  • BatchSize(可选)- 在单个批次中发送用于处理的最大消息数。此值必须在1到10000之间。对于FIFO队列,允许的最大值是10。默认值是10。
  • MaximumBatchingWindowInSeconds(可选)- 在调用函数之前聚集记录的最大时间,以秒为单位。此值必须在0到300之间。默认值为0。当BatchSize设置为大于10的值时,必须将MaximumBatchingWindowInSeconds设置为至少1。如果事件源映射创建用于FIFO队列,则必须不设置此属性。
  • Filters(可选)- 一组由分号(;)分隔的字符串集合,其中每个字符串表示一个模式。只有符合至少一个模式的SQS消息才会被转发到Lambda函数进行处理。
  • MaximumConcurrency(可选)- SQS队列可以触发的最大并发Lambda调用数。此值必须在2到1000之间。默认值为1000。

SQSEvent属性必须与LambdaFunction属性一起应用在Lambda方法上。

当Lambda方法带标签SQSEvent时,它必须遵守以下规则:

  1. 它必须至少有1个参数,最多有2个参数。
    • 第一个参数是必需的,并且必须为在Amazon.Lambda.SQSEvents软件包中定义的SQSEvent类型。
    • 第二个参数是可选的,并且必须为在Amazon.Lambda.Core软件包中定义的ILambdaContext类型。
  2. 方法返回类型必须是以下之一:`void`、`Task`、`SQSBatchResponse` 或 `Task`。`SQSBatchResponse` 类型定义在Amazon.Lambda.SQSEvents 包中。如果返回类型是 `SQSBatchResponse` 或 `Task`,则事件源映射中的 FunctionResponseTypes 设置为报告 ReportBatchItemFailures

[LambdaFunction(ResourceName = "SQSMessageHandler", Policies = "AWSLambdaSQSQueueExecutionRole", PackageType = LambdaPackageType.Image)]
[SQSEvent("@TestQueue", ResourceName = "TestQueueEvent", BatchSize = 50, MaximumConcurrency = 5, MaximumBatchingWindowInSeconds = 5, Filters = "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }")]
public SQSBatchResponse HandleMessage(SQSEvent evnt, ILambdaContext lambdaContext)
{
    lambdaContext.Logger.Log($"Received {evnt.Records.Count} messages");
    return new SQSBatchResponse();
}

在上面的示例中,TestQueue 指的是在 CloudFormation 模板中存在的 SQS 队列资源。

将为 SQSMessageHandler Lambda 函数生成以下 SQS 事件源映射

    "SQSMessageHandler": {
      "Type": "AWS::Serverless::Function",
      "Metadata": {
        "Tool": "Amazon.Lambda.Annotations",
        "SyncedEvents": [
          "TestQueueEvent"
        ]
      },
      "Properties": {
        "MemorySize": 512,
        "Timeout": 30,
        "Policies": [
          "AWSLambdaSQSQueueExecutionRole"
        ],
        "PackageType": "Image",
        "ImageUri": ".",
        "ImageConfig": {
          "Command": [
            "TestServerlessApp::TestServerlessApp.SqsMessageProcessing_HandleMessage_Generated::HandleMessage"
          ]
        },
        "Events": {
          "TestQueueEvent": {
            "Type": "SQS",
            "Properties": {
              "Queue": {
                "Fn::GetAtt": [
                  "TestQueue",
                  "Arn"
                ]
              },
              "BatchSize": 50,
              "FilterCriteria": {
                "Filters": [
                  {
                    "Pattern": "{ \"body\" : { \"RequestCode\" : [ \"BBBB\" ] } }"
                  }
                ]
              },
              "FunctionResponseTypes": [
                "ReportBatchItemFailures"
              ],
              "MaximumBatchingWindowInSeconds": 5,
              "ScalingConfig": {
                "MaximumConcurrency": 5
              }
            }
          }
        }
      }
    },
    "TestQueue": {
      "Type": "AWS::SQS::Queue"
    }

获取构建信息

源生成器在与 MSBuild 编译器错误和警告报告集合并有问题时集成。

要查看源生成器生成的代码,请执行构建时将详细程度设置为详细。在命令中,这可以通过使用 --verbosity 开关完成。

dotnet build --verbosity detailed

要在 Visual Studio 中更改详细程度,请转到“工具”→“选项”→“项目和解决方案”,然后调整 MSBuild 详细程度下拉框。

Lambda .NET 属性参考

支持的 .NET 属性列表。

  • LambdaFunction
    • 放置在方法上。表示该方法应公开为 Lambda 函数。
  • LambdaStartup
    • 放置在类上。表示该类型应用作启动类,并用于配置依赖注入和中间件。Lambda 项目中只能有一个类具有此属性。

事件属性

事件属性配置源生成器以期望事件类型,并在 CloudFormation 模板中设置事件源。如果未设置事件属性,则 LambdaFunction 的参数必须是事件对象,并且必须在代码外部配置事件源。

  • RestApi
    • 配置 Lambda 函数以从 API Gateway REST API 调用。必须在属性上设置 HTTP 方法和资源路径。
  • HttpApi
    • 配置 Lambda 函数以从 API Gateway HTTP API 调用。必须在属性上设置 HTTP 方法、HTTP API 负载版本和资源路径。
  • SQSEvent
    • 设置 Lambda 函数与 SQS 队列之间的事件源映射。必须在属性上设置 SQS 队列 ARN。如果用户希望传递对他们在 CloudFormation 模板中定义的现有 SQS 队列资源的引用,他们可以传递以 @" 符号开头的 SQS 队列资源名称。

参数属性

  • FromHeader
    • 将方法参数映射到 HTTP 头值
  • FromQuery
    • 将方法参数映射到查询字符串参数
  • FromRoute
    • 将方法参数映射到资源路径段
  • FromBody
    • 将方法参数映射到 HTTP 请求正文。如果参数是复杂类型,则请求正文将被假定为 JSON,并反序列化到该类型。
  • FromServices
    • 将方法参数映射到 IServiceProvider 中注册的服务

自定义 API Gateway Lambda 函数的响应

属性 RestApiHttpApi 配置一个 LambdaFunction 方法使用 API Gateway 作为函数的事件源。默认情况下,这些方法返回 HTTP 状态码 200。要自定义 HTTP 响应(包括添加 HTTP 头),方法签名必须返回 Amazon.Lambda.Annotations.APIGateway.IHttpResultTask。`Amazon.Lambda.Annotations.APIGateway.HttpResults` 类包含创建具有适当的 HTTP 状态码和头的 IHttpResult 实例的静态方法。

下面的示例显示了如何返回带有响应正文和自定义头的 HTTP 状态码 404。

[LambdaFunction(PackageType = LambdaPackageType.Image)]
[HttpApi(LambdaHttpMethod.Get, "/resource/{id}")]
public IHttpResult NotFoundResponseWithHeaderV2(int id, ILambdaContext context)
{
    return HttpResults.NotFound($"Resource with id {id} could not be found")
                        .AddHeader("Custom-Header1", "Value1");
}

创建 IHttpResult 实例的可用静态方法。

  • HttpResults.Accepted()
  • HttpResults.BadGateway()
  • HttpResults.BadRequest()
  • HttpResults.Conflict()
  • HttpResults.Created()
  • HttpResults.Forbid()
  • HttpResults.InternalServerError()
  • HttpResults.NotFound()
  • HttpResults.Ok()
  • HttpResults.Redirect()
  • HttpResults.ServiceUnavailable()
  • HttpResults.Unauthorized()
  • HttpResults.NewResult()
内容类型

HttpResults 会自动为响应分配内容类型,如果存在响应体且未使用 AddHeader 方法指定内容类型。内容类型根据以下规则确定。

  • 当响应体是字符串时,内容类型将设置为 text/plain
  • 当响应体是 Streambyte[]IList<byte> 时,内容类型将设置为 application/octet-stream
  • 对于任何其他响应体,内容类型设置为 application/json

项目引用

如果正在使用 API 网关事件属性,例如 RestAPIHttpAPI,则必须将 Amazon.Lambda.APIGatewayEvents 的包引用添加到项目中,否则项目无法编译。我们没有默认包含它,以保持 Amazon.Lambda.Annotations 库轻量。

产品 兼容和附加计算目标框架版本。
.NET net6.0 兼容。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
兼容目标框架
包含的目标框架(在包中)
了解有关 目标框架.NET 标准 的更多信息。

NuGet 包

该包没有被任何 NuGet 包使用。

GitHub 仓库 (4)

显示依赖于Amazon.Lambda.Annotations的GitHub上最受欢迎的前4个仓库

仓库 星标
aws/aws-lambda-dotnet
为.NET Core开发者提供库、示例和工具,以帮助他们开发AWS Lambda函数。
aws-samples/serverless-test-samples
该仓库旨在为实施全面测试套件提供无服务器应用程序的指导。
hlaueriksson/CommandQuery
适用于🌐ASP.NET Core ⚡AWS Lambda ⚡Azure Functions ⚡Google Cloud Functions的命令查询分离
Particular/docs.particular.net
ParticularDocs的全部内容
版本 下载 最后更新
1.5.0 37,169 6/18/2024
1.4.0 27,204 5/16/2024
1.3.1 39,431 4/25/2024
1.3.0 65,832 4/5/2024
1.2.0 113,585 2/16/2024
1.1.0 94,234 11/16/2023
1.0.0 166,810 7/14/2023
0.13.5 10,603 6/23/2023
0.13.4 2,150 6/19/2023
0.13.3 17,427 5/8/2023
0.13.2 10,742 4/24/2023
0.13.1 23,523 4/7/2023
0.13.0 29,180 3/1/2023
0.12.0 38,939 2/14/2023
0.11.0 2,096 2/8/2023
0.10.0-preview 13,442 12/8/2022
0.9.0-preview 4,605 10/26/2022
0.8.0-preview 2,540 9/13/2022
0.7.0-preview 240 8/29/2022
0.6.0-preview 1,627 8/2/2022
0.5.1-preview 2,149 5/3/2022
0.5.0-preview 15,453 2/17/2022
0.4.3-preview 899 1/22/2022
0.4.2-preview 264 12/22/2021