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)
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..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
@@ -20,7 +20,7 @@
true
false
- 1.6.3
+ 1.7.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/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.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/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
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.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..e1e62a038
--- /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#{ANNOTATIONS_ASSEMBLY_VERSION}");
+
+ 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..94e4d7da9
--- /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 (v{ANNOTATIONS_ASSEMBLY_VERSION}).",
+ "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/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");
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/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
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",
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;
}