Table of Contents
The Lambda Annotations Framework provides a programming model for .NET developers to create AWS Lambda Functions.
We saw how the Annotations Framework makes the development experience with Lambda Functions very similar to building APIs using ASP NET Core Framework.
Another feature that the Annotations Framework provides is support for Dependency Injection. This takes the development experience with Lambda Functions a level up.
In this post let’s learn how to setup Dependency Injection when building Lambda Functions using the Annotations Framework.
This article is sponsored by AWS and is part of my AWS Series.
Setting Up DI In .NET Lambda Annotations
Lamba Annotations provides the
LambdaStartup attribute that can be applied on any class in the Lambda Function Project.
The class must have a method
ConfigureServices taking in the
IServiceCollection to set up the Dependency Injection container.
Below I have the
Startup class which has the method specified and the
LambdaStartup attribute applied.
public class Startup
public void ConfigureServices(IServiceCollection services)
The function sets up and registers the different dependencies in the service collection.
Injecting Dependencies in .NET Lambda Function
The Annotations framework supports injecting dependencies through the constructor or through the Lambda Function entry point itself.
Constructor Level DI in Lambda Function
To inject the dependency through the constructor is very similar to how we do DI in .NET. All we need to do is specify the interface dependency in the constructor as shown below.
private readonly IMyDependency _myDependencyCtor;
public Function(IMyDependency myDependencyCtor)
_myDependencyCtor = myDependencyCtor;
The above code injects the
IDependency we registered in the
Startup class to the Function class.
We can store this as a class-level property and use it in our Lambda Function code.
Function Level DI in Lambda Function
You can also inject a dependency through the Function parameters by adding the
public List<string> Add(int a, int b, ILambdaContext lambdaContext, [FromServices] IDependency scopedDependencyFunc)
var returnValues = new List<string>
(a + b).ToString()
The annotation framework uses this attribute to determine that it's a dependency to be resolved from the DI ServiceCollection container and uses it to resolve and pass the appropriate values when invoking the Function code.
DI Service Lifetimes and Lambda Lifecycle
The ServiceCollection supports three lifetimes when registering dependencies.
- Transient → New instance created every request
- Scoped → Instance created once per client request
- Singleton → Single instance of dependency created
However, this is dependent on the lifecycle of the Lambda Functions.
The Lambda Function class is created only once, during the Init phase of the Lambda lifecycle. Once the instance is created it is reused for the same calls handled by the Lambda instance.
It's up to the AWS Lambda infrastructure to decide when to create a new Lambda instance. When the function is just deployed, the Lambda runtime wipes out all existing instances and creates new instances for subsequent requests.
Learn more about Lambda Lifecycle in the below blog post.
The lifetime scope of the dependencies injected via the Service collection is dependent on the Lambda instance.
For example, a singleton instance is only singleton in the context of one Lambda instance. If you have multiple parallel calls coming to your API Gateway, Lambda might decide to spin up multiple Lambda instances and each of them will have its own Singleton instance.
All application state information must be managed outside of Lambda - like in a database or an external Cache service etc.
Under the Hoods of DI in Lambda Annotation Framework
As we have seen previously, the annotations framework generates a wrapper class around our actual Function code class for each
LambdaFunction attributed function.
This wrapper class is where all of the boilerplate code is auto-generated using .NET Source Generators.
Below you can see in the generated class, it creates a new instance of the .NET
ServiceCollection which is the DI container where we are registering the dependencies in the
Function class is registered as a Singleton instance in the DI container.
If needed you can override this to a different lifetime scope inside the
Startup class. Since the last registration wins, anything in the Startup class ConfigureServices method will override the auto-generated registration set up in the wrapper.
The wrapper Function code uses the ServiceCollection instance to resolve the actual function class and any Function parameter dependencies.
The generated function class wraps around the actual function and invokes the function we have written passing in the appropriate dependencies.
You can find the full source code here.
Rahul Nath Newsletter
Join the newsletter to receive the latest updates in your inbox.