From 242ecfa3778064e60882b884852f0d0c62979896 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Wed, 5 Mar 2025 14:47:21 -0600 Subject: [PATCH 1/8] Configure IHostApplicationBuilder support for annotation library (#1999) --- .../792302e7-fe01-4ebe-9357-577bc4097f41.json | 11 ++ ....Lambda.Annotations.SourceGenerator.csproj | 2 +- .../Diagnostics/AnalyzerReleases.Shipped.md | 8 +- .../Diagnostics/DiagnosticDescriptors.cs | 10 +- .../Generator.cs | 36 +++-- .../Models/GeneratedMethodModelBuilder.cs | 10 +- .../Models/LambdaFunctionModelBuilder.cs | 2 +- .../Models/LambdaMethodModel.cs | 6 +- .../Models/LambdaMethodModelBuilder.cs | 3 +- .../SemanticModelProvider.cs | 36 ++++- .../Templates/FieldsAndConstructor.cs | 110 +++++++++++--- .../Templates/FieldsAndConstructor.tt | 35 ++++- ....Annotations.SourceGenerators.Tests.csproj | 18 +++ .../CSharpSourceGeneratorVerifier.cs | 9 +- .../HostBuilderFunctions_Add_Generated.g.cs | 136 ++++++++++++++++++ .../hostbuild.serverless.template | 42 ++++++ .../SourceGeneratorTests.cs | 36 +++++ .../CalculatorService/CalculatorService.cs | 14 ++ .../CalculatorService/ICalculatorService.cs | 19 +++ .../HostBuilderFunctions.cs | 25 ++++ Libraries/test/TestHostBuilderApp/Startup.cs | 15 ++ .../TestHostBuilderApp.csproj | 32 +++++ .../aws-lambda-tools-defaults.json | 15 ++ .../TestHostBuilderApp/serverless.template | 50 +++++++ 24 files changed, 633 insertions(+), 47 deletions(-) create mode 100644 .autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json create mode 100644 Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs create mode 100644 Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template create mode 100644 Libraries/test/TestHostBuilderApp/CalculatorService/CalculatorService.cs create mode 100644 Libraries/test/TestHostBuilderApp/CalculatorService/ICalculatorService.cs create mode 100644 Libraries/test/TestHostBuilderApp/HostBuilderFunctions.cs create mode 100644 Libraries/test/TestHostBuilderApp/Startup.cs create mode 100644 Libraries/test/TestHostBuilderApp/TestHostBuilderApp.csproj create mode 100644 Libraries/test/TestHostBuilderApp/aws-lambda-tools-defaults.json create mode 100644 Libraries/test/TestHostBuilderApp/serverless.template diff --git a/.autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json b/.autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json new file mode 100644 index 000000000..f705a7a98 --- /dev/null +++ b/.autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json @@ -0,0 +1,11 @@ +{ + "Projects": [ + { + "Name": "Amazon.Lambda.Annotations", + "Type": "Minor", + "ChangelogMessages": [ + "Add ConfigureHostBuilder function to `Startup` class for allowing the Lambda function to configure an `IHostApplicationBuilder`." + ] + } + ] +} \ No newline at end of file diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj index a16372d85..c1440bd37 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;net6.0;net8.0 diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/AnalyzerReleases.Shipped.md b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/AnalyzerReleases.Shipped.md index 15312b1a9..adaf1d4b9 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/AnalyzerReleases.Shipped.md +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/AnalyzerReleases.Shipped.md @@ -1,6 +1,12 @@ ; Shipped analyzer releases ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md +## Release 1.7.0 +### New Rules +Rule ID | Category | Severity | Notes +--------|----------|----------|------- +AWSLambda0119 | AWSLambdaCSharpGenerator | Error | Conflicting Service Configuration Methods Detected + ## Release 1.5.1 ### New Rules @@ -79,4 +85,4 @@ Rule ID | Category | Severity | Notes AWSLambda0001 | AWSLambda | Error | Unhandled exception AWSLambda0101 | AWSLambdaCSharpGenerator | Error | Multiple LambdaStartup classes not allowed AWSLambda0102 | AWSLambdaCSharpGenerator | Error | Multiple events on Lambda function not supported -AWSLambda0103 | AWSLambdaCSharpGenerator | Info | Generated code \ No newline at end of file +AWSLambda0103 | AWSLambdaCSharpGenerator | Info | Generated code diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/DiagnosticDescriptors.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/DiagnosticDescriptors.cs index f3561f433..a606e5e88 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/DiagnosticDescriptors.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Diagnostics/DiagnosticDescriptors.cs @@ -145,5 +145,13 @@ public static class DiagnosticDescriptors category: "AWSLambdaCSharpGenerator", DiagnosticSeverity.Error, isEnabledByDefault: true); + + public static readonly DiagnosticDescriptor MultipleConfigureMethodsNotAllowed = new DiagnosticDescriptor( + id: "AWSLambda0119", + title: "Conflicting Service Configuration Methods Detected", + messageFormat: "Both '{0}' and '{1}' methods are present. Only {1} will be used. Please consolidate your service configuration into {1}.", + category: "AWSLambdaCSharpGenerator", + DiagnosticSeverity.Error, + isEnabledByDefault: true); } -} \ No newline at end of file +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Generator.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Generator.cs index ee14afd19..69ef75620 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Generator.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Generator.cs @@ -1,4 +1,4 @@ -using Amazon.Lambda.Annotations.SourceGenerator.Diagnostics; +using Amazon.Lambda.Annotations.SourceGenerator.Diagnostics; using Amazon.Lambda.Annotations.SourceGenerator.Extensions; using Amazon.Lambda.Annotations.SourceGenerator.FileIO; using Amazon.Lambda.Annotations.SourceGenerator.Models; @@ -93,9 +93,9 @@ public void Execute(GeneratorExecutionContext context) var isExecutable = false; bool foundFatalError = false; - + var assemblyAttributes = context.Compilation.Assembly.GetAttributes(); - + var globalPropertiesAttribute = assemblyAttributes .FirstOrDefault(attr => attr.AttributeClass.Name == nameof(LambdaGlobalPropertiesAttribute)); @@ -109,7 +109,7 @@ public void Execute(GeneratorExecutionContext context) defaultRuntime = _targetFrameworksToRuntimes[targetFramework]; } } - + // The runtime specified in the global property has precedence over the one we determined from the TFM (if we did) if (globalPropertiesAttribute != null) { @@ -134,14 +134,26 @@ public void Execute(GeneratorExecutionContext context) } } - var configureMethodSymbol = semanticModelProvider.GetConfigureMethodModel(receiver.StartupClasses.FirstOrDefault()); + var configureHostBuilderMethodSymbol = semanticModelProvider.GetConfigureHostBuilderMethodModel(receiver.StartupClasses.FirstOrDefault()); + var configureServicesMethodSymbol = semanticModelProvider.GetConfigureServicesMethodModel(receiver.StartupClasses.FirstOrDefault()); + var configureMethodSymbol = configureServicesMethodSymbol; + + if (configureServicesMethodSymbol != null && configureHostBuilderMethodSymbol != null) + { + diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.MultipleConfigureMethodsNotAllowed, configureServicesMethodSymbol.Locations.FirstOrDefault(), configureServicesMethodSymbol.Name, configureHostBuilderMethodSymbol.Name)); + } + + if (configureHostBuilderMethodSymbol != null) + { + configureMethodSymbol = configureHostBuilderMethodSymbol; + } var annotationReport = new AnnotationReport(); var templateHandler = new CloudFormationTemplateHandler(_fileManager, _directoryManager); var lambdaModels = new List(); - + foreach (var lambdaMethodDeclarationSyntax in receiver.LambdaMethods) { var lambdaMethodSymbol = semanticModelProvider.GetMethodSemanticModel(lambdaMethodDeclarationSyntax); @@ -163,7 +175,7 @@ public void Execute(GeneratorExecutionContext context) sourceText = template.TransformText().ToEnvironmentLineEndings(); context.AddSource($"{lambdaFunctionModel.GeneratedMethod.ContainingType.Name}.g.cs", SourceText.From(sourceText, Encoding.UTF8, SourceHashAlgorithm.Sha256)); } - catch (Exception e) when (e is NotSupportedException || e is InvalidOperationException) + catch (Exception e) when (e is NotSupportedException || e is InvalidOperationException) { diagnosticReporter.Report(Diagnostic.Create(DiagnosticDescriptors.CodeGenerationFailed, Location.Create(lambdaMethodDeclarationSyntax.SyntaxTree, lambdaMethodDeclarationSyntax.Span), e.Message)); return; @@ -241,7 +253,7 @@ private static ExecutableAssembly GenerateExecutableAssemblySource( DiagnosticDescriptors.MissingDependencies, Location.None, "Amazon.Lambda.RuntimeSupport")); - + return null; } @@ -251,14 +263,14 @@ private static ExecutableAssembly GenerateExecutableAssemblySource( var symbol = model.GetDeclaredSymbol(methodDeclaration) as IMethodSymbol; // Check to see if a static main method exists in the same namespace that has 0 or 1 parameters - if (symbol.Name != "Main" || !symbol.IsStatic || symbol.ContainingNamespace.Name != lambdaModels[0].LambdaMethod.ContainingAssembly || (symbol.Parameters.Length > 1)) + if (symbol.Name != "Main" || !symbol.IsStatic || symbol.ContainingNamespace.Name != lambdaModels[0].LambdaMethod.ContainingAssembly || (symbol.Parameters.Length > 1)) continue; - + diagnosticReporter.Report( Diagnostic.Create( DiagnosticDescriptors.MainMethodExists, Location.None)); - + return null; } @@ -284,4 +296,4 @@ public void Initialize(GeneratorInitializationContext context) context.RegisterForSyntaxNotifications(() => new SyntaxReceiver(_fileManager, _directoryManager)); } } -} \ No newline at end of file +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/GeneratedMethodModelBuilder.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/GeneratedMethodModelBuilder.cs index 87a413b2c..f39a1d440 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/GeneratedMethodModelBuilder.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/GeneratedMethodModelBuilder.cs @@ -27,7 +27,7 @@ public static GeneratedMethodModel Build(IMethodSymbol lambdaMethodSymbol, return model; } - private static IList BuildUsings(LambdaMethodModel lambdaMethodModel, + private static IList BuildUsings(LambdaMethodModel lambdaMethodModel, IMethodSymbol lambdaMethodSymbol, IMethodSymbol configureMethodSymbol, GeneratorExecutionContext context) @@ -45,6 +45,12 @@ private static IList BuildUsings(LambdaMethodModel lambdaMethodModel, if (configureMethodSymbol != null) { namespaces.Add("Microsoft.Extensions.DependencyInjection"); + + if (lambdaMethodModel.UsingHostBuilderForDependencyInjection) + { + namespaces.Add("Microsoft.Extensions.Hosting"); + } + } namespaces.Add("Amazon.Lambda.Core"); @@ -73,7 +79,7 @@ private static TypeModel BuildResponseType(IMethodSymbol lambdaMethodSymbol, return TypeModelBuilder.Build(typeStream, context); } - + if (lambdaMethodSymbol.HasAttribute(context, TypeFullNames.RestApiAttribute)) { var symbol = lambdaMethodModel.ReturnsVoidOrGenericTask ? diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaFunctionModelBuilder.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaFunctionModelBuilder.cs index f347789a7..e828bee3d 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaFunctionModelBuilder.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaFunctionModelBuilder.cs @@ -83,4 +83,4 @@ private static LambdaSerializerInfo GetSerializerInfoAttribute(GeneratorExecutio return new LambdaSerializerInfo(serializerString); } } -} \ No newline at end of file +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModel.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModel.cs index 24caa34c1..06d032eff 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModel.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModel.cs @@ -54,7 +54,7 @@ public bool ReturnsIHttpResults { return true; } - if(ReturnsGenericTask && ReturnType.TypeArguments.Count == 1 && ReturnType.TypeArguments[0].FullName == TypeFullNames.IHttpResult) + if(ReturnsGenericTask && ReturnType.TypeArguments.Count == 1 && ReturnType.TypeArguments[0].FullName == TypeFullNames.IHttpResult) { return true; } @@ -100,6 +100,8 @@ public bool ReturnsVoidTaskOrSqsBatchResponse /// public bool UsingDependencyInjection { get; set; } + public bool UsingHostBuilderForDependencyInjection { get; set; } + /// /// Gets or sets the namespace for the nearest enclosing namespace. Returns null if the /// symbol isn't contained in a namespace. @@ -151,4 +153,4 @@ public AttributeModel LambdaFunctionAttribute } } } -} \ No newline at end of file +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModelBuilder.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModelBuilder.cs index 3dccfce7e..5c1347b3a 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModelBuilder.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Models/LambdaMethodModelBuilder.cs @@ -27,10 +27,11 @@ public static LambdaMethodModel Build(IMethodSymbol lambdaMethodSymbol, Events = EventTypeBuilder.Build(lambdaMethodSymbol, context), ContainingType = TypeModelBuilder.Build(lambdaMethodSymbol.ContainingType, context), UsingDependencyInjection = configureMethodSymbol != null, + UsingHostBuilderForDependencyInjection = configureMethodSymbol != null && configureMethodSymbol.Name == "ConfigureHostBuilder", Attributes = lambdaMethodSymbol.GetAttributes().Select(att => AttributeModelBuilder.Build(att, context)).ToList() }; return model; } } -} \ No newline at end of file +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/SemanticModelProvider.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/SemanticModelProvider.cs index 076e61672..84aeb2e68 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/SemanticModelProvider.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/SemanticModelProvider.cs @@ -20,14 +20,14 @@ public SemanticModelProvider(GeneratorExecutionContext context) /// If is null, returns null. /// /// LambdaStartup attributed class syntax - public IMethodSymbol GetConfigureMethodModel(ClassDeclarationSyntax startupSyntax) + public IMethodSymbol GetConfigureServicesMethodModel(ClassDeclarationSyntax startupSyntax) { if (startupSyntax == null) { return null; } - IMethodSymbol configureMethodSymbol = null; + IMethodSymbol configureServicesMethodSymbol = null; var iServiceCollectionSymbol = _context.Compilation.GetTypeByMetadataName("Microsoft.Extensions.DependencyInjection.IServiceCollection"); @@ -36,7 +36,6 @@ public IMethodSymbol GetConfigureMethodModel(ClassDeclarationSyntax startupSynta // Filter the methods which can potentially have Configure(IServiceCollection) parameter signature var members = startupSyntax.Members.Where(member => member.Kind() == SyntaxKind.MethodDeclaration); - foreach (var member in members) { var methodSyntax = (MethodDeclarationSyntax) member; @@ -47,12 +46,37 @@ public IMethodSymbol GetConfigureMethodModel(ClassDeclarationSyntax startupSynta && methodSymbol.Parameters[0].Type .Equals(iServiceCollectionSymbol, SymbolEqualityComparer.Default)) { - configureMethodSymbol = methodSymbol; + configureServicesMethodSymbol = methodSymbol; + break; + } + } + + return configureServicesMethodSymbol; + } + + public IMethodSymbol GetConfigureHostBuilderMethodModel(ClassDeclarationSyntax startupSyntax) + { + if (startupSyntax == null) + { + return null; + } + + IMethodSymbol configureHostBuilderMethodSymbol = null; + + var classModel = _context.Compilation.GetSemanticModel(startupSyntax.SyntaxTree); + + foreach (var member in startupSyntax.Members.Where(member => member.Kind() == SyntaxKind.MethodDeclaration)) + { + var methodSyntax = (MethodDeclarationSyntax)member; + var methodSymbol = classModel.GetDeclaredSymbol(methodSyntax); + if (methodSymbol != null && methodSymbol.Name == "ConfigureHostBuilder") + { + configureHostBuilderMethodSymbol = methodSymbol; break; } } - return configureMethodSymbol; + return configureHostBuilderMethodSymbol; } /// @@ -65,4 +89,4 @@ public IMethodSymbol GetMethodSemanticModel(MethodDeclarationSyntax syntax) return methodModel.GetDeclaredSymbol(syntax); } } -} \ No newline at end of file +} diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.cs b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.cs index 7354994e9..37d50c71b 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.cs +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version: 17.0.0.0 @@ -42,6 +42,24 @@ public virtual string TransformText() #line 12 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + if (_model.LambdaMethod.UsingHostBuilderForDependencyInjection) + { + + + #line default + #line hidden + this.Write(" private readonly IHost host;\r\n"); + + #line 17 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + + } + + + #line default + #line hidden + + #line 20 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + } else { @@ -51,28 +69,28 @@ public virtual string TransformText() #line hidden this.Write(" private readonly "); - #line 17 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 25 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); #line default #line hidden this.Write(" "); - #line 17 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 25 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name.ToCamelCase())); #line default #line hidden this.Write(";\r\n private readonly "); - #line 18 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 26 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.SerializerInfo.SerializerName)); #line default #line hidden this.Write(" serializer;\r\n"); - #line 19 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 27 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" } @@ -87,18 +105,75 @@ public virtual string TransformText() /// public "); - #line 28 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 36 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.GeneratedMethod.ContainingType.Name)); #line default #line hidden this.Write("()\r\n {\r\n SetExecutionEnvironment();\r\n"); - #line 31 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 39 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" if (_model.LambdaMethod.UsingDependencyInjection) { + if (_model.LambdaMethod.UsingHostBuilderForDependencyInjection) + { + + + #line default + #line hidden + this.Write(" var startup = new "); + + #line 46 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(_model.StartupType.FullName)); + + #line default + #line hidden + this.Write(@"(); + var hostBuilder = startup.ConfigureHostBuilder(); + + // 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. + hostBuilder.Services.AddSingleton<"); + + #line 51 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); + + #line default + #line hidden + this.Write(">();\r\n hostBuilder.Services.AddSingleton<"); + + #line 52 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(_model.SerializerInfo.SerializerName)); + + #line default + #line hidden + this.Write(">();\r\n\r\n serviceProvider = hostBuilder.Services.BuildServiceProvider()" + + ";\r\n\r\n host = hostBuilder.Build();\r\n host.RunAsync();\r\n\r\n " + + " // Intentionally eagerly build "); + + #line 59 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); + + #line default + #line hidden + this.Write(" and its dependencies.\r\n // This causes time spent in the Constructor " + + "to appear on INIT_REPORTs\r\n _ = serviceProvider.GetRequiredService<"); + + #line 61 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); + + #line default + #line hidden + this.Write(">();\r\n"); + + #line 62 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + + } + else + { + #line default #line hidden @@ -108,21 +183,21 @@ public virtual string TransformText() // To use a different lifetime, specify the lifetime in Startup.ConfigureServices(IServiceCollection) method. services.AddSingleton<"); - #line 39 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 71 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); #line default #line hidden this.Write(">();\r\n services.AddSingleton<"); - #line 40 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 72 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.SerializerInfo.SerializerName)); #line default #line hidden this.Write(">();\r\n\r\n var startup = new "); - #line 42 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 74 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.StartupType.FullName)); #line default @@ -131,7 +206,7 @@ public virtual string TransformText() "r = services.BuildServiceProvider();\r\n\r\n // Intentionally eagerly bui" + "ld "); - #line 46 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 78 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); #line default @@ -139,15 +214,16 @@ public virtual string TransformText() this.Write(" and its dependencies.\r\n // This causes time spent in the Constructor " + "to appear on INIT_REPORTs\r\n _ = serviceProvider.GetRequiredService<"); - #line 48 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 80 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); #line default #line hidden this.Write(">();\r\n"); - #line 49 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 81 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + } } else { @@ -157,28 +233,28 @@ public virtual string TransformText() #line hidden this.Write(" "); - #line 54 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 87 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name.ToCamelCase())); #line default #line hidden this.Write(" = new "); - #line 54 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 87 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.LambdaMethod.ContainingType.Name)); #line default #line hidden this.Write("();\r\n serializer = new "); - #line 55 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 88 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" this.Write(this.ToStringHelper.ToStringWithCulture(_model.SerializerInfo.SerializerName)); #line default #line hidden this.Write("();\r\n"); - #line 56 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" + #line 89 "C:\projects\aws\aws-lambda-dotnet\Libraries\src\Amazon.Lambda.Annotations.SourceGenerator\Templates\FieldsAndConstructor.tt" } diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.tt b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.tt index 5260488cd..35a1f2c59 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.tt +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Templates/FieldsAndConstructor.tt @@ -1,4 +1,4 @@ -<#@ template language="C#" #> +<#@ template language="C#" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> @@ -9,6 +9,14 @@ { #> private readonly ServiceProvider serviceProvider; +<# + if (_model.LambdaMethod.UsingHostBuilderForDependencyInjection) + { +#> + private readonly IHost host; +<# + } +#> <# } else @@ -31,6 +39,30 @@ <# if (_model.LambdaMethod.UsingDependencyInjection) { + + if (_model.LambdaMethod.UsingHostBuilderForDependencyInjection) + { +#> + var startup = new <#= _model.StartupType.FullName #>(); + var hostBuilder = startup.ConfigureHostBuilder(); + + // 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. + hostBuilder.Services.AddSingleton<<#= _model.LambdaMethod.ContainingType.Name #>>(); + hostBuilder.Services.AddSingleton<<#= _model.SerializerInfo.SerializerName #>>(); + + serviceProvider = hostBuilder.Services.BuildServiceProvider(); + + host = hostBuilder.Build(); + host.RunAsync(); + + // Intentionally eagerly build <#= _model.LambdaMethod.ContainingType.Name #> and its dependencies. + // This causes time spent in the Constructor to appear on INIT_REPORTs + _ = serviceProvider.GetRequiredService<<#= _model.LambdaMethod.ContainingType.Name #>>(); +<# + } + else + { #> var services = new ServiceCollection(); @@ -47,6 +79,7 @@ // This causes time spent in the Constructor to appear on INIT_REPORTs _ = serviceProvider.GetRequiredService<<#= _model.LambdaMethod.ContainingType.Name #>>(); <# + } } else { diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj index b44099d2b..3682b71a9 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Amazon.Lambda.Annotations.SourceGenerators.Tests.csproj @@ -29,6 +29,7 @@ + @@ -41,6 +42,15 @@ + + TestHostBuilderApp\%(RecursiveDir)/%(FileName)%(Extension) + Always + + + + + + TestServerlessApp.NET8\%(RecursiveDir)/%(FileName)%(Extension) Always @@ -114,6 +124,14 @@ PreserveNewest + + PreserveNewest + + + + PreserveNewest + + PreserveNewest diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs index f785c8fd5..7f42bb85b 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/CSharpSourceGeneratorVerifier.cs @@ -1,4 +1,4 @@ -using Amazon.Lambda.Annotations.APIGateway; +using Amazon.Lambda.Annotations.APIGateway; using Amazon.Lambda.APIGatewayEvents; using Amazon.Lambda.Core; using Amazon.Lambda.RuntimeSupport; @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Testing.Verifiers; using Microsoft.CodeAnalysis.Text; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using System; using System.Collections.Immutable; using System.IO; @@ -40,6 +41,8 @@ public Test(ReferencesMode referencesMode = ReferencesMode.All, TargetFramework .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(ServiceProvider).Assembly.Location)) .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(RestApiAttribute).Assembly.Location)) .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(DefaultLambdaJsonSerializer).Assembly.Location)) + .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(HostApplicationBuilder).Assembly.Location)) + .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(IHost).Assembly.Location)) .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(LambdaBootstrapBuilder).Assembly.Location)); }); @@ -55,6 +58,8 @@ public Test(ReferencesMode referencesMode = ReferencesMode.All, TargetFramework .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(ServiceProvider).Assembly.Location)) .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(RestApiAttribute).Assembly.Location)) .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(DefaultLambdaJsonSerializer).Assembly.Location)) + .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(HostApplicationBuilder).Assembly.Location)) + .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(IHost).Assembly.Location)) .AddMetadataReference(projectId, MetadataReference.CreateFromFile(typeof(LambdaBootstrapBuilder).Assembly.Location)); }); } @@ -128,4 +133,4 @@ protected override ParseOptions CreateParseOptions() } } } -} \ No newline at end of file +} diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs new file mode 100644 index 000000000..a4e1e8bde --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs @@ -0,0 +1,136 @@ +// + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Amazon.Lambda.Core; + +namespace TestHostBuilderApp +{ + public class HostBuilderFunctions_Add_Generated + { + private readonly ServiceProvider serviceProvider; + private readonly IHost host; + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public HostBuilderFunctions_Add_Generated() + { + SetExecutionEnvironment(); + var startup = new TestHostBuilderApp.Startup(); + var hostBuilder = startup.ConfigureHostBuilder(); + + // 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. + hostBuilder.Services.AddSingleton(); + hostBuilder.Services.AddSingleton(); + + serviceProvider = hostBuilder.Services.BuildServiceProvider(); + + host = hostBuilder.Build(); + host.RunAsync(); + + // Intentionally eagerly build HostBuilderFunctions and its dependencies. + // This causes time spent in the Constructor to appear on INIT_REPORTs + _ = serviceProvider.GetRequiredService(); + } + + /// + /// The generated Lambda function handler for + /// + /// The API Gateway request object that will be processed by the Lambda function handler. + /// The ILambdaContext that provides methods for logging and describing the Lambda environment. + /// Result of the Lambda function execution + 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 hostBuilderFunctions = scope.ServiceProvider.GetRequiredService(); + var serializer = scope.ServiceProvider.GetRequiredService(); + + var validationErrors = new List(); + + 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()) + { + var errorResult = new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Body = @$"{{""message"": ""{validationErrors.Count} validation error(s) detected: {string.Join(",", validationErrors)}""}}", + Headers = new Dictionary + { + {"Content-Type", "application/json"}, + {"x-amzn-ErrorType", "ValidationException"} + }, + StatusCode = 400 + }; + return errorResult; + } + + var response = hostBuilderFunctions.Add(x, y, __context__); + + var body = response.ToString(); + + return new Amazon.Lambda.APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse + { + Body = body, + Headers = new Dictionary + { + {"Content-Type", "application/json"} + }, + StatusCode = 200 + }; + } + + private static void SetExecutionEnvironment() + { + const string envName = "AWS_EXECUTION_ENV"; + + var envValue = new StringBuilder(); + + // If there is an existing execution environment variable add the annotations package as a suffix. + if(!string.IsNullOrEmpty(Environment.GetEnvironmentVariable(envName))) + { + envValue.Append($"{Environment.GetEnvironmentVariable(envName)}_"); + } + + envValue.Append("lib/amazon-lambda-annotations#1.6.3.0"); + + Environment.SetEnvironmentVariable(envName, envValue.ToString()); + } + } +} \ No newline at end of file diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template new file mode 100644 index 000000000..f12b63f0d --- /dev/null +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template @@ -0,0 +1,42 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.6.3.0).", + "Resources": { + "TestHostBuilderAppHostBuilderFunctionsAddGenerated": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } + }, + "Properties": { + "Runtime": "dotnet6", + "CodeUri": ".", + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Zip", + "Handler": "TestProject::TestHostBuilderApp.HostBuilderFunctions_Add_Generated::Add", + "Events": { + "RootGet": { + "Type": "HttpApi", + "Properties": { + "Path": "/add/{x}/{y}", + "Method": "GET" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs index dd5f70fb2..f3d622232 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/SourceGeneratorTests.cs @@ -1364,6 +1364,42 @@ public async Task ExceededMaximumHandlerLength() }.RunAsync(); } + [Fact] + public async Task HostBuilder() + { + var expectedAddGenerated = await ReadSnapshotContent(Path.Combine("Snapshots", "HostBuilderFunctions_Add_Generated.g.cs")); + var expectedTemplate = await ReadSnapshotContent(Path.Combine("Snapshots", "ServerlessTemplates", "hostbuild.serverless.template")); + + await new VerifyCS.Test + { + TestState = + { + Sources = + { + (Path.Combine("TestHostBuilderApp", "HostBuilderFunctions.cs"), await File.ReadAllTextAsync(Path.Combine("TestHostBuilderApp", "HostBuilderFunctions.cs"))), + (Path.Combine("TestHostBuilderApp", "Startup.cs"), await File.ReadAllTextAsync(Path.Combine("TestHostBuilderApp", "Startup.cs"))), + (Path.Combine("TestHostBuilderApp", "CalculatorService", "ICalculatorService.cs"), await File.ReadAllTextAsync(Path.Combine("TestHostBuilderApp", "CalculatorService", "ICalculatorService.cs"))), + (Path.Combine("TestHostBuilderApp", "CalculatorService", "CalculatorService.cs"), await File.ReadAllTextAsync(Path.Combine("TestHostBuilderApp", "CalculatorService", "CalculatorService.cs"))), + + }, + GeneratedSources = + { + ( + typeof(SourceGenerator.Generator), + "HostBuilderFunctions_Add_Generated.g.cs", + SourceText.From(expectedAddGenerated, Encoding.UTF8, SourceHashAlgorithm.Sha256) + ), + + }, + ExpectedDiagnostics = + { + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments("HostBuilderFunctions_Add_Generated.g.cs", expectedAddGenerated), + new DiagnosticResult("AWSLambda0103", DiagnosticSeverity.Info).WithArguments($"TestHostBuilderApp{Path.DirectorySeparatorChar}serverless.template", expectedTemplate), + } + } + }.RunAsync(); + } + public void Dispose() { File.Delete(Path.Combine("TestServerlessApp", "serverless.template")); diff --git a/Libraries/test/TestHostBuilderApp/CalculatorService/CalculatorService.cs b/Libraries/test/TestHostBuilderApp/CalculatorService/CalculatorService.cs new file mode 100644 index 000000000..5ebe406b2 --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/CalculatorService/CalculatorService.cs @@ -0,0 +1,14 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +namespace TestHostBuilderApp +{ + public class CalculatorService : ICalculatorService + { + /// + public int Add(int x, int y) + { + return x + y; + } + } +} diff --git a/Libraries/test/TestHostBuilderApp/CalculatorService/ICalculatorService.cs b/Libraries/test/TestHostBuilderApp/CalculatorService/ICalculatorService.cs new file mode 100644 index 000000000..de14af39a --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/CalculatorService/ICalculatorService.cs @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +namespace TestHostBuilderApp +{ + /// + /// An interface for a service that implements the business logic of our Lambda functions + /// + public interface ICalculatorService + { + /// + /// Adds x and y together + /// + /// Addend + /// Addend + /// Sum of x and y + int Add(int x, int y); + } +} diff --git a/Libraries/test/TestHostBuilderApp/HostBuilderFunctions.cs b/Libraries/test/TestHostBuilderApp/HostBuilderFunctions.cs new file mode 100644 index 000000000..3f5c1ed52 --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/HostBuilderFunctions.cs @@ -0,0 +1,25 @@ +using Amazon.Lambda.Core; +using Amazon.Lambda.Annotations; +using Amazon.Lambda.Annotations.APIGateway; + +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace TestHostBuilderApp; + +public class HostBuilderFunctions +{ + private ICalculatorService _calculatorService; + + public HostBuilderFunctions(ICalculatorService calculatorService) + { + _calculatorService = calculatorService; + } + + [LambdaFunction()] + [HttpApi(LambdaHttpMethod.Get, "/add/{x}/{y}")] + public int Add(int x, int y, ILambdaContext context) + { + var sum = _calculatorService.Add(x, y); + return sum; + } +} diff --git a/Libraries/test/TestHostBuilderApp/Startup.cs b/Libraries/test/TestHostBuilderApp/Startup.cs new file mode 100644 index 000000000..acc0fc8bf --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/Startup.cs @@ -0,0 +1,15 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace TestHostBuilderApp; + +[Amazon.Lambda.Annotations.LambdaStartup] +public class Startup +{ + public HostApplicationBuilder ConfigureHostBuilder() + { + var builder = new HostApplicationBuilder(); + builder.Services.AddSingleton(new CalculatorService()); + return builder; + } +} diff --git a/Libraries/test/TestHostBuilderApp/TestHostBuilderApp.csproj b/Libraries/test/TestHostBuilderApp/TestHostBuilderApp.csproj new file mode 100644 index 000000000..e75db6450 --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/TestHostBuilderApp.csproj @@ -0,0 +1,32 @@ + + + Library + net8.0 + enable + enable + true + Lambda + + true + + true + + + + + + + + + + + + + + + + diff --git a/Libraries/test/TestHostBuilderApp/aws-lambda-tools-defaults.json b/Libraries/test/TestHostBuilderApp/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..456fef59b --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/aws-lambda-tools-defaults.json @@ -0,0 +1,15 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "s3-prefix": "TestHostBuilderApp/", + "template": "serverless.template", + "template-parameters": "", + "docker-host-build-output-dir": "./bin/Release/lambda-publish" +} \ No newline at end of file diff --git a/Libraries/test/TestHostBuilderApp/serverless.template b/Libraries/test/TestHostBuilderApp/serverless.template new file mode 100644 index 000000000..58fba9d49 --- /dev/null +++ b/Libraries/test/TestHostBuilderApp/serverless.template @@ -0,0 +1,50 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Transform": "AWS::Serverless-2016-10-31", + "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.6.3.0).", + "Resources": { + "TestHostBuilderAppHostBuilderFunctionsAddGenerated": { + "Type": "AWS::Serverless::Function", + "Metadata": { + "Tool": "Amazon.Lambda.Annotations", + "SyncedEvents": [ + "RootGet" + ], + "SyncedEventProperties": { + "RootGet": [ + "Path", + "Method" + ] + } + }, + "Properties": { + "Runtime": "dotnet8", + "CodeUri": ".", + "MemorySize": 512, + "Timeout": 30, + "Policies": [ + "AWSLambdaBasicExecutionRole" + ], + "PackageType": "Zip", + "Handler": "TestHostBuilderApp::TestHostBuilderApp.HostBuilderFunctions_Add_Generated::Add", + "Events": { + "RootGet": { + "Type": "HttpApi", + "Properties": { + "Path": "/add/{x}/{y}", + "Method": "GET" + } + } + } + } + } + }, + "Outputs": { + "ApiURL": { + "Description": "API endpoint URL for Prod environment", + "Value": { + "Fn::Sub": "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/" + } + } + } +} \ No newline at end of file From 633fefabea610e8ba85c4bb9d47c6a93ecb9535b Mon Sep 17 00:00:00 2001 From: Phil Asmar Date: Thu, 6 Mar 2025 09:55:33 -0500 Subject: [PATCH 2/8] chore: add cfn tag to integ tests --- .../Helpers/CloudFormationHelper.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Helpers/CloudFormationHelper.cs b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Helpers/CloudFormationHelper.cs index cf440cf35..1fc1a1ee6 100644 --- a/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Helpers/CloudFormationHelper.cs +++ b/Tools/LambdaTestTool-v2/tests/Amazon.Lambda.TestTool.IntegrationTests/Helpers/CloudFormationHelper.cs @@ -21,7 +21,12 @@ public async Task CreateStackAsync(string stackName, string templateBody { StackName = stackName, TemplateBody = templateBody, - Capabilities = new List { "CAPABILITY_IAM" } + Capabilities = new List { "CAPABILITY_IAM" }, + Tags = new List + { + new Tag { Key = "aws-tests", Value = typeof(CloudFormationHelper).FullName }, + new Tag { Key = "aws-repo", Value = "aws-lambda-dotnet" } + } }); return response.StackId; } From afc5853a159a19ac89b78adbb0a24745145f0b1d Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Wed, 12 Mar 2025 16:22:21 -0400 Subject: [PATCH 3/8] fix test (#2011) --- .../Snapshots/HostBuilderFunctions_Add_Generated.g.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs index a4e1e8bde..e1e62a038 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/HostBuilderFunctions_Add_Generated.g.cs @@ -128,7 +128,7 @@ private static void SetExecutionEnvironment() envValue.Append($"{Environment.GetEnvironmentVariable(envName)}_"); } - envValue.Append("lib/amazon-lambda-annotations#1.6.3.0"); + envValue.Append("lib/amazon-lambda-annotations#{ANNOTATIONS_ASSEMBLY_VERSION}"); Environment.SetEnvironmentVariable(envName, envValue.ToString()); } From 70f35d619772f18cd0ad446ee0d62632fae998f4 Mon Sep 17 00:00:00 2001 From: Garrett Beatty Date: Thu, 13 Mar 2025 13:12:30 -0400 Subject: [PATCH 4/8] fix test (#2013) --- .../Snapshots/ServerlessTemplates/hostbuild.serverless.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template index f12b63f0d..94e4d7da9 100644 --- a/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template +++ b/Libraries/test/Amazon.Lambda.Annotations.SourceGenerators.Tests/Snapshots/ServerlessTemplates/hostbuild.serverless.template @@ -1,7 +1,7 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::Serverless-2016-10-31", - "Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.6.3.0).", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v{ANNOTATIONS_ASSEMBLY_VERSION}).", "Resources": { "TestHostBuilderAppHostBuilderFunctionsAddGenerated": { "Type": "AWS::Serverless::Function", From b0d7cce24b8da9145c06f9c578e5371e7d94c72c Mon Sep 17 00:00:00 2001 From: Norm Johanson Date: Thu, 13 Mar 2025 11:09:54 -0700 Subject: [PATCH 5/8] Update global logger to support logging with level and arguments. (#2005) --- .../d0822afd-daf4-437a-9437-2a9492c135b7.json | 18 +++++ .../src/Amazon.Lambda.Core/LambdaLogger.cs | 71 ++++++++++++++++++- .../Helpers/ConsoleLoggerWriter.cs | 25 ++++--- .../CustomRuntimeTests.cs | 17 ++++- .../CustomRuntimeFunction.cs | 14 +++- 5 files changed, 132 insertions(+), 13 deletions(-) create mode 100644 .autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json diff --git a/.autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json b/.autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json new file mode 100644 index 000000000..28f238342 --- /dev/null +++ b/.autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json @@ -0,0 +1,18 @@ +{ + "Projects": [ + { + "Name": "Amazon.Lambda.RuntimeSupport", + "Type": "Minor", + "ChangelogMessages": [ + "Add support for parameterized logging method to global logger LambdaLogger in Amazon.Lambda.Core" + ] + }, + { + "Name": "Amazon.Lambda.Core", + "Type": "Patch", + "ChangelogMessages": [ + "Add support for parameterized logging method to global logger LambdaLogger. Method is marked as preview till new version of Amazon.Lambda.RuntimeSupport is deployed to managed runtime." + ] + } + ] +} \ No newline at end of file diff --git a/Libraries/src/Amazon.Lambda.Core/LambdaLogger.cs b/Libraries/src/Amazon.Lambda.Core/LambdaLogger.cs index 554d3b4e1..c6b612bcf 100644 --- a/Libraries/src/Amazon.Lambda.Core/LambdaLogger.cs +++ b/Libraries/src/Amazon.Lambda.Core/LambdaLogger.cs @@ -1,4 +1,7 @@ -using System; +using System; +using System.Reflection.Emit; +using System.Runtime.Versioning; +using System.Text; namespace Amazon.Lambda.Core { @@ -9,8 +12,11 @@ namespace Amazon.Lambda.Core /// public static class LambdaLogger { - // Logging action, logs to Console by default + // The name of this field must not change or be readonly because Amazon.Lambda.RuntimeSupport will use reflection to replace the + // value with an Action that directs the logging into its logging system. +#pragma warning disable IDE0044 // Add readonly modifier private static Action _loggingAction = LogToConsole; +#pragma warning restore IDE0044 // Add readonly modifier // Logs message to console private static void LogToConsole(string message) @@ -29,5 +35,66 @@ public static void Log(string message) { _loggingAction(message); } + +#if NET6_0_OR_GREATER + + // The name of this field must not change or be readonly because Amazon.Lambda.RuntimeSupport will use reflection to replace the + // value with an Action that directs the logging into its logging system. +#pragma warning disable IDE0044 // Add readonly modifier + private static Action _loggingWithLevelAction = LogWithLevelToConsole; +#pragma warning restore IDE0044 // Add readonly modifier + + // Logs message to console + private static void LogWithLevelToConsole(string level, string message, params object[] args) + { + // Formatting here is not important, it is used for debugging Amazon.Lambda.Core only. + // In a real scenario Amazon.Lambda.RuntimeSupport will change the value of _loggingWithLevelAction + // to an Action inside it's logging system to handle the real formatting. + var sb = new StringBuilder(); + sb.Append(level).Append(": ").Append(message); + if (args?.Length > 0) + { + sb.Append(" Arguments:"); + foreach(var arg in args) + { + sb.Append(" \""); + sb.Append(arg); + sb.Append("\""); + } + } + Console.WriteLine(sb.ToString()); + } + + private const string ParameterizedPreviewMessage = + "This method has been mark as preview till the Lambda .NET Managed runtime has been updated with the backing implementation of this method. " + + "It is possible to use this method while in preview if the Lambda function is deployed as an executable and uses the latest version of Amazon.Lambda.RuntimeSupport."; + + /// + /// Logs a message to AWS CloudWatch Logs. + /// + /// Logging will not be done: + /// If the role provided to the function does not have sufficient permissions. + /// + /// The log level of the message + /// Message to log. The message may have format arguments. + /// Arguments to format the message with. + [RequiresPreviewFeatures(ParameterizedPreviewMessage)] + public static void Log(string level, string message, params object[] args) + { + _loggingWithLevelAction(level, message, args); + } + + /// + /// Logs a message to AWS CloudWatch Logs. + /// + /// Logging will not be done: + /// If the role provided to the function does not have sufficient permissions. + /// + /// The log level of the message + /// Message to log. The message may have format arguments. + /// Arguments to format the message with. + [RequiresPreviewFeatures(ParameterizedPreviewMessage)] + public static void Log(LogLevel level, string message, params object[] args) => Log(level.ToString(), message, args); +#endif } } diff --git a/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs b/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs index 15d577060..18417e562 100644 --- a/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs +++ b/Libraries/src/Amazon.Lambda.RuntimeSupport/Helpers/ConsoleLoggerWriter.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). @@ -240,16 +240,25 @@ private void Initialize(TextWriter stdOutWriter, TextWriter stdErrorWriter) /// private void ConfigureLoggingActionField() { - var lambdaILoggerType = typeof(Amazon.Lambda.Core.LambdaLogger); - if (lambdaILoggerType == null) + var lambdaLoggerType = typeof(Amazon.Lambda.Core.LambdaLogger); + if (lambdaLoggerType == null) return; - var loggingActionField = lambdaILoggerType.GetTypeInfo().GetField("_loggingAction", BindingFlags.NonPublic | BindingFlags.Static); - if (loggingActionField == null) - return; + var loggingActionField = lambdaLoggerType.GetTypeInfo().GetField("_loggingAction", BindingFlags.NonPublic | BindingFlags.Static); + if (loggingActionField != null) + { + Action loggingAction = (message => FormattedWriteLine(null, message)); + loggingActionField.SetValue(null, loggingAction); + } + - Action callback = (message => FormattedWriteLine(null, message)); - loggingActionField.SetValue(null, callback); + var loggingWithLevelActionField = lambdaLoggerType.GetTypeInfo().GetField("_loggingWithLevelAction", BindingFlags.NonPublic | BindingFlags.Static); + if (loggingWithLevelActionField != null) + { + Action loggingWithLevelAction = ((level, message, args) => FormattedWriteLine(level, message, args)); + loggingWithLevelActionField.SetValue(null, loggingWithLevelAction); + + } } /// diff --git a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeTests.cs b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeTests.cs index 4ab778a30..387245e63 100644 --- a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeTests.cs +++ b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/Amazon.Lambda.RuntimeSupport.IntegrationTests/CustomRuntimeTests.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). @@ -106,6 +106,7 @@ protected virtual async Task TestAllHandlersAsync() await RunTestSuccessAsync(lambdaClient, "UnintendedDisposeTest", "not-used", "UnintendedDisposeTest-SUCCESS"); await RunTestSuccessAsync(lambdaClient, "LoggingStressTest", "not-used", "LoggingStressTest-success"); + await RunGlobalLoggingTestAsync(lambdaClient, "GlobalLoggingTest"); await RunJsonLoggingWithUnhandledExceptionAsync(lambdaClient); await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Trace, LogConfigSource.LambdaAPI); @@ -121,7 +122,6 @@ protected virtual async Task TestAllHandlersAsync() await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Error, LogConfigSource.DotnetEnvironment); await RunLoggingTestAsync(lambdaClient, "LoggingTest", RuntimeLogLevel.Critical, LogConfigSource.DotnetEnvironment); - await RunUnformattedLoggingTestAsync(lambdaClient, "LoggingTest"); await RunTestSuccessAsync(lambdaClient, "ToUpperAsync", "message", "ToUpperAsync-MESSAGE"); @@ -317,6 +317,19 @@ private async Task RunLoggingTestAsync(AmazonLambdaClient lambdaClient, string h } } + private async Task RunGlobalLoggingTestAsync(AmazonLambdaClient lambdaClient, string handler) + { + await UpdateHandlerAsync(lambdaClient, handler); + + var invokeResponse = await InvokeFunctionAsync(lambdaClient, JsonConvert.SerializeObject("")); + Assert.True(invokeResponse.HttpStatusCode == System.Net.HttpStatusCode.OK); + Assert.True(invokeResponse.FunctionError == null); + + var log = System.Text.UTF8Encoding.UTF8.GetString(Convert.FromBase64String(invokeResponse.LogResult)); + + Assert.Contains("This is a global log message with foobar as an argument", log); + } + private async Task RunUnformattedLoggingTestAsync(AmazonLambdaClient lambdaClient, string handler) { var environmentVariables = new Dictionary(); diff --git a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeFunctionTest/CustomRuntimeFunction.cs b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeFunctionTest/CustomRuntimeFunction.cs index c803a20f6..7cd6ec3b0 100644 --- a/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeFunctionTest/CustomRuntimeFunction.cs +++ b/Libraries/test/Amazon.Lambda.RuntimeSupport.Tests/CustomRuntimeFunctionTest/CustomRuntimeFunction.cs @@ -1,4 +1,4 @@ -using Amazon.Lambda.Core; +using Amazon.Lambda.Core; using Amazon.Lambda.RuntimeSupport; using Amazon.Lambda.Serialization.SystemTextJson; using System; @@ -48,6 +48,9 @@ private static async Task Main(string[] args) case nameof(LoggingStressTest): bootstrap = new LambdaBootstrap(LoggingStressTest); break; + case nameof(GlobalLoggingTest): + bootstrap = new LambdaBootstrap(GlobalLoggingTest); + break; case nameof(LoggingTest): bootstrap = new LambdaBootstrap(LoggingTest); break; @@ -169,6 +172,15 @@ Task UseLoggerAsync() return Task.FromResult(GetInvocationResponse(nameof(LoggingStressTest), "success")); } + + private static Task GlobalLoggingTest(InvocationRequest invocation) + { +#pragma warning disable CA2252 + LambdaLogger.Log(LogLevel.Information, "This is a global log message with {argument} as an argument", "foobar"); +#pragma warning restore CA2252 + return Task.FromResult(GetInvocationResponse(nameof(GlobalLoggingTest), true)); + } + private static Task LoggingTest(InvocationRequest invocation) { invocation.LambdaContext.Logger.LogTrace("A trace log"); From 4d5cd31c0218ed5a003a89d8a5231b781c897d7f Mon Sep 17 00:00:00 2001 From: aws-sdk-dotnet-automation Date: Thu, 13 Mar 2025 18:14:27 +0000 Subject: [PATCH 6/8] release_2025-03-13 --- .../Amazon.Lambda.Annotations.SourceGenerator.csproj | 4 ++-- .../Amazon.Lambda.Annotations.csproj | 2 +- Libraries/src/Amazon.Lambda.Core/Amazon.Lambda.Core.csproj | 2 +- .../Amazon.Lambda.RuntimeSupport.csproj | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj index c1440bd37..ca772979c 100644 --- a/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj +++ b/Libraries/src/Amazon.Lambda.Annotations.SourceGenerator/Amazon.Lambda.Annotations.SourceGenerator.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;net6.0;net8.0 @@ -20,7 +20,7 @@ true false - 1.6.3 + 1.7.0 diff --git a/Libraries/src/Amazon.Lambda.Annotations/Amazon.Lambda.Annotations.csproj b/Libraries/src/Amazon.Lambda.Annotations/Amazon.Lambda.Annotations.csproj index e73c47589..ab216f029 100644 --- a/Libraries/src/Amazon.Lambda.Annotations/Amazon.Lambda.Annotations.csproj +++ b/Libraries/src/Amazon.Lambda.Annotations/Amazon.Lambda.Annotations.csproj @@ -11,7 +11,7 @@ ..\..\..\buildtools\public.snk true - 1.6.3 + 1.7.0 diff --git a/Libraries/src/Amazon.Lambda.Core/Amazon.Lambda.Core.csproj b/Libraries/src/Amazon.Lambda.Core/Amazon.Lambda.Core.csproj index c6a034fe0..8fb5f7029 100644 --- a/Libraries/src/Amazon.Lambda.Core/Amazon.Lambda.Core.csproj +++ b/Libraries/src/Amazon.Lambda.Core/Amazon.Lambda.Core.csproj @@ -6,7 +6,7 @@ netstandard2.0;net6.0;net8.0 Amazon Lambda .NET Core support - Core package. Amazon.Lambda.Core - 2.5.0 + 2.5.1 Amazon.Lambda.Core Amazon.Lambda.Core AWS;Amazon;Lambda diff --git a/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj b/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj index 282bd6095..47ce7f796 100644 --- a/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj +++ b/Libraries/src/Amazon.Lambda.RuntimeSupport/Amazon.Lambda.RuntimeSupport.csproj @@ -4,7 +4,7 @@ netstandard2.0;net6.0;net8.0;net9.0 - 1.12.3 + 1.13.0 Provides a bootstrap and Lambda Runtime API Client to help you to develop custom .NET Core Lambda Runtimes. Amazon.Lambda.RuntimeSupport Amazon.Lambda.RuntimeSupport From d047062dbb333d2fff2338feb21254d7f0f509e7 Mon Sep 17 00:00:00 2001 From: aws-sdk-dotnet-automation Date: Thu, 13 Mar 2025 18:15:24 +0000 Subject: [PATCH 7/8] Update test app CloudFormation templates --- Libraries/test/TestExecutableServerlessApp/serverless.template | 2 +- Libraries/test/TestServerlessApp.NET8/serverless.template | 2 +- Libraries/test/TestServerlessApp/serverless.template | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/test/TestExecutableServerlessApp/serverless.template b/Libraries/test/TestExecutableServerlessApp/serverless.template index 5e24942a0..eb837db65 100644 --- a/Libraries/test/TestExecutableServerlessApp/serverless.template +++ b/Libraries/test/TestExecutableServerlessApp/serverless.template @@ -1,7 +1,7 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::Serverless-2016-10-31", - "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.6.3.0).", + "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.7.0.0).", "Parameters": { "ArchitectureTypeParameter": { "Type": "String", diff --git a/Libraries/test/TestServerlessApp.NET8/serverless.template b/Libraries/test/TestServerlessApp.NET8/serverless.template index e665f904e..1b591183a 100644 --- a/Libraries/test/TestServerlessApp.NET8/serverless.template +++ b/Libraries/test/TestServerlessApp.NET8/serverless.template @@ -1,7 +1,7 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::Serverless-2016-10-31", - "Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.6.3.0).", + "Description": "This template is partially managed by Amazon.Lambda.Annotations (v1.7.0.0).", "Resources": { "TestServerlessAppNET8FunctionsToUpperGenerated": { "Type": "AWS::Serverless::Function", diff --git a/Libraries/test/TestServerlessApp/serverless.template b/Libraries/test/TestServerlessApp/serverless.template index 53e145fd6..06d788b8f 100644 --- a/Libraries/test/TestServerlessApp/serverless.template +++ b/Libraries/test/TestServerlessApp/serverless.template @@ -1,7 +1,7 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Transform": "AWS::Serverless-2016-10-31", - "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.6.3.0).", + "Description": "An AWS Serverless Application. This template is partially managed by Amazon.Lambda.Annotations (v1.7.0.0).", "Parameters": { "ArchitectureTypeParameter": { "Type": "String", From 2e59f624a944db8ae4f575a02fa2f4da3f5beb4e Mon Sep 17 00:00:00 2001 From: aws-sdk-dotnet-automation Date: Thu, 13 Mar 2025 18:15:26 +0000 Subject: [PATCH 8/8] Updated changelog --- .../792302e7-fe01-4ebe-9357-577bc4097f41.json | 11 ----------- .../d0822afd-daf4-437a-9437-2a9492c135b7.json | 18 ------------------ CHANGELOG.md | 9 +++++++++ 3 files changed, 9 insertions(+), 29 deletions(-) delete mode 100644 .autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json delete mode 100644 .autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json diff --git a/.autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json b/.autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json deleted file mode 100644 index f705a7a98..000000000 --- a/.autover/changes/792302e7-fe01-4ebe-9357-577bc4097f41.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "Projects": [ - { - "Name": "Amazon.Lambda.Annotations", - "Type": "Minor", - "ChangelogMessages": [ - "Add ConfigureHostBuilder function to `Startup` class for allowing the Lambda function to configure an `IHostApplicationBuilder`." - ] - } - ] -} \ No newline at end of file diff --git a/.autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json b/.autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json deleted file mode 100644 index 28f238342..000000000 --- a/.autover/changes/d0822afd-daf4-437a-9437-2a9492c135b7.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "Projects": [ - { - "Name": "Amazon.Lambda.RuntimeSupport", - "Type": "Minor", - "ChangelogMessages": [ - "Add support for parameterized logging method to global logger LambdaLogger in Amazon.Lambda.Core" - ] - }, - { - "Name": "Amazon.Lambda.Core", - "Type": "Patch", - "ChangelogMessages": [ - "Add support for parameterized logging method to global logger LambdaLogger. Method is marked as preview till new version of Amazon.Lambda.RuntimeSupport is deployed to managed runtime." - ] - } - ] -} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f1bb900bb..52ac30d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +## Release 2025-03-13 + +### Amazon.Lambda.Annotations (1.7.0) +* Add ConfigureHostBuilder function to `Startup` class for allowing the Lambda function to configure an `IHostApplicationBuilder`. +### Amazon.Lambda.RuntimeSupport (1.13.0) +* Add support for parameterized logging method to global logger LambdaLogger in Amazon.Lambda.Core +### Amazon.Lambda.Core (2.5.1) +* Add support for parameterized logging method to global logger LambdaLogger. Method is marked as preview till new version of Amazon.Lambda.RuntimeSupport is deployed to managed runtime. + ## Release 2025-03-05 ### Amazon.Lambda.TestTool (0.9.1)