Demonstrates how to add .NET Core dependency injection and configuration services to an AWS Lambda Function project for .NET Core 2.1.
The idea behind this approach is to leverage the built-in configuration system of .NET Core, which can accept mulitple inputs that can override one another. This allows for use of an appsettings.json file with settings entries that can be overriden by environment variables applied when the Lambda Function is deployed. This allows for values that will be available when debugging the function locally, as well as values that can be set as part of a CICD pipeline.
- Visual Studio 2017 or greater.
- AWS Toolkit for Visual Studio 2017.
- .NET Core 2.1 SDK
-
Open VS 2017 and create a new project.
- Select AWS Lambda Project with Tests.
-
Add version 2.1 following NuGet Packages
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.EnvironmentVariables
- Microsoft.Extensions.Configuration.FileExtensions
- Microsoft.Extensions.Configuration.Json
- Microsoft.Extensions.DependencyInjection
-
Add an appsettings.json file to the project.
- Add the following content:
{ "env1": "val1", "env2": "val2", "env3": "val3" }
-
Add an appsettings.Development.json file to the project.
- Add the following content:
{ "env1": "dev-val1", "env2": "dev-val2", "env3": "dev-val3" }
-
Select both JSON files, open the Propeties window of Visual Studio, then set the
BuildAction
property to Content and theCopy to Output Directory
property to Copy always. -
Open the aws-lambda-tools-defaults.json file and add the following:
"environment-variables" : "\"ASPNETCORE_ENVIRONMENT\"=\"Development\";\"env1\"=\"val1\";\"env2\"=\"val2\"",
-
Add an
environmentVariables
property to the launchSettings.json file."environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" }
-
Add a
Constants
class to the project.public static class Constants { public static class EnvironmentVariables { public const string AspnetCoreEnvironment = "ASPNETCORE_ENVIRONMENT"; } public static class Environments { public const string Production = "Production"; } }
-
Add a
IEnvironmentService
interface to the project.public interface IEnvironmentService { string EnvironmentName { get; set; } }
-
Add a
EnvironmentService
class to the project.public class EnvironmentService : IEnvironmentService { public EnvironmentService() { EnvironmentName = Environment.GetEnvironmentVariable(EnvironmentVariables.AspnetCoreEnvironment) ?? Environments.Production; } public string EnvironmentName { get; set; } }
-
Add a
IConfigurationService
interface to the project.public interface IConfigurationService { IConfiguration GetConfiguration(); }
-
Add a
ConfigurationService
class to the project.public class ConfigurationService : IConfigurationService { public IConfiguration GetConfiguration() { return new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json") .AddEnvironmentVariables() .Build(); } }
-
Add a
ConfigureServices
method to theFunction
class in order to register services with the DI system.private void ConfigureServices(IServiceCollection serviceCollection) { // Register services with DI system serviceCollection.AddTransient<IEnvironmentService, EnvironmentService>(); serviceCollection.AddTransient<IConfigurationService, ConfigurationService>(); }
-
Add a property and two constructors to the
Function
class.// Configuration Service public IConfigurationService ConfigService { get; } public Function() { // Set up Dependency Injection var serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); var serviceProvider = serviceCollection.BuildServiceProvider(); // Get Configuration Service from DI system ConfigService = serviceProvider.GetService<IConfigurationService>(); } // Use this ctor from unit tests that can mock IConfigurationService public Function(IConfigurationService configService) { ConfigService = configService; }
-
Flesh out the
FunctionHandler
method to use theConfigService
.- Use the input parameter for the key used to retrieve a setting.
public string FunctionHandler(string input, ILambdaContext context) { // Get config setting using input as a key return ConfigService.GetConfiguration()[input] ?? "None"; }
-
Press F5 to launch the Mock Lambda Test Tool and start debugging.
-
Enter
"env1"
into Function Input, and click Execute Function.- A value of
"val1"
should be returned base on the appsettings.json file.
- A value of
-
Add the NuGet package for Moq to the Test project.
-
Add a reference to the NetCoreLambda project.
-
Mock
IConfiguration
(from Microsoft.Extensions.Configuration) to return the expected value.var expected = "val1"; var mockConfig = new Mock<IConfiguration>(); mockConfig.Setup(p => p[It.IsAny<string>()]).Returns(expected);
-
Mock
IConfigurationService
to return the mockIConfiguration
.var mockConfigService = new Mock<IConfigurationService>(); mockConfigService.Setup(p => p.GetConfiguration()).Returns(mockConfig.Object);
-
Invoke the lambda function and confirm config value is returned.
var function = new Function(mockConfigService.Object); var result = function.FunctionHandler("env1", new TestLambdaContext()); Assert.Equal(expected, result);
-
Right-click on the project in the Solutions Explorer and select Publish to AWS Lambda.
-
Under Configuration you can change the values for the environment variables, and these will override the values from the appsettings.json file published with the Lambda Function.
Once you have edited your template and code you can deploy your application using the Amazon.Lambda.Tools Global Tool from the command line.
Install Amazon.Lambda.Tools Global Tools if not already installed.
dotnet tool install -g Amazon.Lambda.Tools
If already installed check if new version is available.
dotnet tool update -g Amazon.Lambda.Tools
Execute unit tests
cd "NetCoreLambda/test/NetCoreLambda.Tests"
dotnet test
Deploy function to AWS Lambda
cd "NetCoreLambda/src/NetCoreLambda"
dotnet lambda deploy-function