10

I've created an empty AWS Lambda project with .net CORE :

enter image description here

Which basically all it yields is a .net core empty lambda function project :

enter image description here

But as it is now - it doesn't support Injection (DI) , since there is no startup file etc ...So basically it is ia .net core project without all its benefits.

However , Tony wrote about it: Add .NET Core DI and Config Goodness to AWS Lambda Functions" :

Basically what he did is to manually make the project support DI.

So I've created a ConfigurationService class :

ConfigureServices.cs

 public interface IConfigurationService
    {
        IConfiguration GetConfiguration();
    }

    public class ConfigurationService : IConfigurationService
    {
        public IConfiguration GetConfiguration()
        {
            return new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables()
                .Build();
        }
    }

And then used it in the code , as in a regular way .

So here is the same function as above returning a key from appSettigs , PLUS (!!!) Dependency Injection:

Function.cs

public class Function
    {
        public Function()
        {
            /*MANUALLY MAKING OUR PROJECT TO SUPPORT DI*/
            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);
            var serviceProvider = serviceCollection.BuildServiceProvider();
            ConfigService = serviceProvider.GetService<IConfigurationService>();
        }

        public IConfigurationService ConfigService { get; }

        private void ConfigureServices(IServiceCollection serviceCollection)
        {
            serviceCollection.AddOptions();
            serviceCollection.AddTransient<IConfigurationService, ConfigurationService>();

        }


        public string FunctionHandler(string input, ILambdaContext context)
        {
            var res = ConfigService.GetConfiguration()["Message"];
            return res;
        }
    }

It does work :

enter image description here

(Here is the appsetting.json file BTW) :

appsettings.json

{
    "Message": "Hello"
}

It also work when I Inject IConfigurationService to other class'es constructor.

So where is the problem?

I want to use the type safe access to the appsettings.json using IOptions.
— So I've created a corresponding file:

AppSettings.cs

 public class AppSettings
    {
        public string Message  { get; set; }
    }

And now I need to configure it , but look what happens:

enter image description here

It first invokes the ConfigureServices method in line #16 , then It Configure the AppSettings at line #27 , and then it crashes(!) at line #27 becuase ConfigService is null. Why is it null ? Because it is only assigned in line #18

Question

What should I do in order for the code to support Configure<Appsettings> ?

1 Answer 1

9

You do not really need IOptions in this scenario and can configure the dependencies as needed

For example review the following

public class Function {
    public static Func<IServiceProvider> ConfigureServices = () => {
        var serviceCollection = new ServiceCollection();
        
        serviceCollection.AddOptions(); //OPTIONAL
        
        //...add additional services as needed
        
        //building configuration
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddEnvironmentVariables()
            .Build();
        
        //Get strongly typed setting from appsettings binding to object graph
        var settings = configuration.Get<AppSettings>();
        // adding to service collection so that it can be resolved/injected as needed.
        serviceCollection.AddSingleton(settings);
        
        return serviceCollection.BuildServiceProvider();
    };

    static IServiceProvider services;
    
    static Function() { //Static ctor invokes once.
        services = ConfigureServices();
    }

    public string FunctionHandler(string input, ILambdaContext context) {
        //...
    
        var settings =  services.GetRequiredService<AppSettings>();
        var message = settings.Message;
        return message;
    }
}

A one time setup of static service provider is configured with the desired settings added to the provider as a strongly typed model which can be resolved and injected as needed.

Sign up to request clarification or add additional context in comments.

12 Comments

After doing var settings = configuration.Get<AppSettings>(); serviceCollection.AddSingleton(settings); - this means that I can inject it to CTOR ? How ? it doesn't have an interface.......
@RoyiNamir classes can also be injected. While most would suggest against it, that is usually for services that provide some functionality. This class is a simple POCO used to store settings and really has no need for an abstraction.
Thanks for the answer. It does work , but However - please notice that now , I can't use IConfigurationServices for Injection in other places. It is possible to Use in your sample , an injected IConfiguration ?
@RoyiNamir I am aware. That was intentional. You really should not be passing around and injecting IConfiguration. Should really be confined to the composition root.
Wow thanks for the enlightenment. Make sense now :-) thank you ! Too bad that AWS didnt use the goodness for DI in the first place .
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.