Skip to content

Commit 39cd8c6

Browse files
authored
LAMBJ-48 Config Factory Example (#59)
Added an example for custom config factories.
1 parent ebf9926 commit 39cd8c6

13 files changed

+166
-1
lines changed

.github/releases/v0.5.0-beta1.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ This release introduces the following:
22

33
- .NET Templates are here! Install via `dotnet new -i Lambdajection.Templates`. Templates are available for both projects and options.
44
- IDisposable and IAsyncDisposable Lambdas are now fully supported. Disposers will be called at the end of each invocation. If you implement both IDisposable and IAsyncDisposable, DisposeAsync will be preferred.
5+
- Added an example for custom config factories.
56
- Upgrades Roslyn to 3.7.0 (via CodeGeneration.Roslyn) for latest bug and security fixes, along with increased nullability checks. Addressed changes around new possible null references.

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
fetch-depth: 0
2525

2626
- name: Get Commit Message
27-
run: echo COMMIT_MESSAGE=$(git log --format=%B -n 1 ${{ github.event.after }} | sed 's/\\n/%0A/g') >> $GITHUB_ENV
27+
run: echo "COMMIT_MESSAGE=$(git log --format=%B -n 1 ${{ github.event.after }} | sed 's/\\n/%0A/g')" >> $GITHUB_ENV
2828

2929
- name: Setup .NET Core
3030
uses: actions/setup-dotnet@v1

README.md

+3
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ namespace Your.Namespace
241241
}
242242
```
243243

244+
See the [full example here](./examples/CustomConfiguration/README.md).
245+
244246
### 4.5. Adding Options
245247

246248
You can add an options section by defining a class for that section, and annotating it with the [LambdaOptions attribute](src/Attributes/LambdaOptionsAttribute.cs). If any options are in encrypted form, add the [Encrypted attribute](src/Encryption/EncryptedAttribute.cs) to that property. When the options are requested, the [IDecryptionService](src/Encryption/IDecryptionService.cs) singleton in the container will be used to decrypt those properties. The [default decryption service](src/Encryption/DefaultDecryptionService.cs) uses KMS to decrypt values.
@@ -289,6 +291,7 @@ Your.Assembly.Name::Your.Namespace.YourLambda::Run
289291
- [Injecting and using AWS Services + Factories](examples/AwsClientFactories)
290292
- [Automatic decryption of encrypted options](examples/EncryptedOptions)
291293
- [Using a custom serializer](examples/CustomSerializer/README.md)
294+
- [Using a custom config factory](examples/CustomConfiguration/README.md)
292295

293296
## 6. Acknowledgments
294297

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using Lambdajection.Attributes;
2+
3+
namespace Lambdajection.Examples.CustomConfiguration
4+
{
5+
[LambdaOptions(typeof(Handler), "Config")]
6+
public class Config
7+
{
8+
public string Foo { get; set; } = "";
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System.IO;
2+
3+
using Lambdajection.Core;
4+
5+
using Microsoft.Extensions.Configuration;
6+
7+
namespace Lambdajection.Examples.CustomConfiguration
8+
{
9+
public class ConfigFactory : ILambdaConfigFactory
10+
{
11+
public IConfigurationRoot Create()
12+
{
13+
return new ConfigurationBuilder()
14+
.SetBasePath(Directory.GetCurrentDirectory())
15+
.AddJsonFile("appsettings.json", optional: true)
16+
.Build();
17+
}
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<NoWarn>IDE0052</NoWarn>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Lambdajection" Version="$(LambdajectionVersion)" />
10+
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.8" />
11+
</ItemGroup>
12+
</Project>
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Threading.Tasks;
2+
3+
using Amazon.Lambda.Core;
4+
5+
using Lambdajection.Attributes;
6+
7+
using Microsoft.Extensions.Options;
8+
9+
namespace Lambdajection.Examples.CustomConfiguration
10+
{
11+
[Lambda(typeof(Startup), ConfigFactory = typeof(ConfigFactory))]
12+
public partial class Handler
13+
{
14+
private readonly Config config;
15+
16+
public Handler(IOptions<Config> config)
17+
{
18+
this.config = config.Value;
19+
}
20+
21+
public Task<string> Handle(object request, ILambdaContext context)
22+
{
23+
return Task.FromResult(config.Foo);
24+
}
25+
}
26+
}
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Custom Configuration Example
2+
3+
It is sometimes useful to add multiple configuration sources. This example illustrates the use of a custom config factory to achieve that.
4+
5+
## Files
6+
7+
- [Lambda Code](Handler.cs)
8+
- [Config Factory Code](ConfigFactory.cs)
9+
- [Startup Code](Startup.cs)
10+
- [CloudFormation Template](cloudformation.template.yml)
11+
12+
## Steps to Recreate
13+
14+
1. Create a new netcoreapp3.1 and add the following packages:
15+
16+
- Lambdajection
17+
18+
2. Create a [ConfigFactory](./ConfigFactory.cs) that enables file-based configuration. Set the ConfigFactory argument in the Lambda Handler attribute to point to your config factory's type.
19+
20+
21+
3. Create a [Config / Options](./Config.cs) class that will be used to hold your configuration items. Inject this class into your handler and read values from it inside the `Handle` method.
22+
23+
24+
4. Add a [Startup Class](Startup.cs) and configure any services that will be injected into your Lambda Handler in here.
25+
26+
5. Create a [CloudFormation template](cloudformation.template.yml) for your Lambda.
27+
- Note that we are using the serverless transform in the example, however using the transform is optional.
28+
29+
## How it Works
30+
31+
1. During a build, the generator will use your config factory in place of [the default one](../../src/Core/LambdaConfigFactory.cs). The type of this class is added as a generic argument to the [Lambda Host](../../src/Core/LambdaHost.cs).
32+
2. When the lambda is run, the [Lambda Host Builder](../../src/Core/LambdaHostBuilder.cs) will create a new instance of your config factory and create a configuration instance using that factory. That config instance will then be added to the service collection / provider passed to the lambda host as well as your startup class.
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Lambdajection.Core;
2+
3+
using Microsoft.Extensions.Configuration;
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace Lambdajection.Examples.CustomConfiguration
7+
{
8+
public class Startup : ILambdaStartup
9+
{
10+
private readonly IConfiguration configuration;
11+
12+
public Startup(IConfiguration configuration)
13+
{
14+
this.configuration = configuration;
15+
}
16+
17+
public void ConfigureServices(IServiceCollection services)
18+
{
19+
// Inject services into the Lambda's container here
20+
}
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"Config": {
3+
"Foo": "Bar"
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Transform: AWS::Serverless-2016-10-31
2+
Resources:
3+
CustomConfiguration:
4+
Type: AWS::Serverless::Function
5+
Properties:
6+
Handler: CustomConfiguration::Lambdajection.Examples.CustomConfiguration.Handler::Run
7+
Runtime: dotnetcore3.1
8+
FunctionName: CustomConfiguration
9+
Timeout: 300
10+
CodeUri: ../../bin/Examples/CustomConfiguration/Release/netcoreapp3.1/publish/
11+
MemorySize: 512
12+
Policies:
13+
- AWSLambdaExecute
14+
15+
Outputs:
16+
InputPayload:
17+
Value: "{}"
18+
19+
ExpectedOutput:
20+
Value: '"Bar"'

examples/examples.sln

+14
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AwsClientFactories", "AwsCl
99
EndProject
1010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSerializer", "CustomSerializer\CustomSerializer.csproj", "{98D76580-934D-450B-9FB5-0D5B76465D22}"
1111
EndProject
12+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomConfiguration", "CustomConfiguration\CustomConfiguration.csproj", "{02804CA8-1838-47C9-9882-9227FD8B923B}"
13+
EndProject
1214
Global
1315
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1416
Debug|Any CPU = Debug|Any CPU
@@ -58,5 +60,17 @@ Global
5860
{98D76580-934D-450B-9FB5-0D5B76465D22}.Release|x64.Build.0 = Release|Any CPU
5961
{98D76580-934D-450B-9FB5-0D5B76465D22}.Release|x86.ActiveCfg = Release|Any CPU
6062
{98D76580-934D-450B-9FB5-0D5B76465D22}.Release|x86.Build.0 = Release|Any CPU
63+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
64+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Debug|Any CPU.Build.0 = Debug|Any CPU
65+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Debug|x64.ActiveCfg = Debug|Any CPU
66+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Debug|x64.Build.0 = Debug|Any CPU
67+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Debug|x86.ActiveCfg = Debug|Any CPU
68+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Debug|x86.Build.0 = Debug|Any CPU
69+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Release|Any CPU.ActiveCfg = Release|Any CPU
70+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Release|Any CPU.Build.0 = Release|Any CPU
71+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Release|x64.ActiveCfg = Release|Any CPU
72+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Release|x64.Build.0 = Release|Any CPU
73+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Release|x86.ActiveCfg = Release|Any CPU
74+
{02804CA8-1838-47C9-9882-9227FD8B923B}.Release|x86.Build.0 = Release|Any CPU
6175
EndGlobalSection
6276
EndGlobal

0 commit comments

Comments
 (0)