如何在AWS Lambda C#实现中使用依赖注入

时间:2017-12-19 13:40:01

标签: c# .net-core aws-lambda

我使用AWS.Net SDK创建了Lambda函数,.net核心版本1.0。我想实现依赖注入。由于lambda函数在AWS环境中独立触发和运行,因此不存在Startup之类的类。如何以及在哪里可以配置我的容器以实现此实现?

4 个答案:

答案 0 :(得分:5)

你可以这样做。您的FunctionHandler是您的应用程序的入口点。因此您必须从那里连接服务集合。

public class Function
{
    public string FunctionHandler(string input, ILambdaContext context)
    {
        var serviceCollection = new ServiceCollection();
        ConfigureServices(serviceCollection);

        // create service provider
        var serviceProvider = serviceCollection.BuildServiceProvider();

        // entry to run app.
        return serviceProvider.GetService<App>().Run(input);
    }

    private static void ConfigureServices(IServiceCollection serviceCollection)
    {
        // add dependencies here

        // here is where you're adding the actual application logic to the collection
        serviceCollection.AddTransient<App>();
    }
}

public class App
{
    // if you put a constructor here with arguments that are wired up in your services collection, they will be injected.

    public string Run(string input)
    {
        return "This is a test";
    }
}

如果您想连接日志记录,请查看此处:https://github.com/aws/aws-lambda-dotnet/tree/master/Libraries/src/Amazon.Lambda.Logging.AspNetCore

答案 1 :(得分:3)

虽然FunctionHandler确实是您进入应用程序的入口点,但实际上我会将您的DI连接到无参数构造函数中。构造函数只会被调用一次,因此,这种纯粹的“设置”代码实际上只需要被调用一次。我们只想在路由到同一容器的每个后续调用中利用它。

public class Function
{
    private static ServiceProvider ServiceProvider { get; set; }

    /// <summary>
    /// The parameterless constructor is what Lambda uses to construct your instance the first time.
    /// It will only ever be called once for the lifetime of the container that it's running on.
    /// We want to build our ServiceProvider once, and then use the same provider in all subsequent 
    /// Lambda invocations. This makes things like using local MemoryCache techniques viable (Just 
    /// remember that you can never count on a locally cached item to be there!)
    /// </summary>
    public Function()
    {
        var services = new ServiceCollection();
        ConfigureServices(services);
        ServiceProvider = services.BuildServiceProvider();
    }

    public async Task FunctionHandler(SQSEvent evnt, ILambdaContext context)
    {
        await ServiceProvider.GetService<App>().Run(evnt);
    }

    /// <summary>
    /// Configure whatever dependency injection you like here
    /// </summary>
    /// <param name="services"></param>
    private static void ConfigureServices(IServiceCollection services)
    {
        // add dependencies here ex: Logging, IMemoryCache, Interface mapping to concrete class, etc...

        // add a hook to your class that will actually do the application logic
        services.AddTransient<App>();
    }

    /// <summary>
    /// Since we don't want to dispose of the ServiceProvider in the FunctionHandler, we will
    /// at least try to clean up after ourselves in the destructor for the class.
    /// </summary>
    ~Function()
    {
        ServiceProvider.Dispose();
    }
}

public class App
{
    public async Task Run(SQSEvent evnt)
    {
        // actual business logic goes here
        await Task.CompletedTask;
    }
}

答案 2 :(得分:3)

我知道我已经很晚了,但是我添加这个是因为我相信互联网上有一些不好的/不足的例子。 @Erndob关于接受的答案是正确的。您将只创建更多实例。

根据您在DI容器中进行的注册情况,您需要谨记:

  1. 您要进行哪些注册以实现IDisposable
  2. AWS将对象实例保留多长时间。我没有找到任何关于此的文档。

最终出现了这样的情况:

public class Function
{
    private ServiceCollection _serviceCollection;

    public Function()
    {
        ConfigureServices();
    }

    public string FunctionHandler(string input, ILambdaContext context)
    {
        using (ServiceProvider serviceProvider = _serviceCollection.BuildServiceProvider())
        {
            // entry to run app.
            return serviceProvider.GetService<App>().Run(input);
        }
    }

    private void ConfigureServices()
    {
        // add dependencies here
        _serviceCollection = new ServiceCollection();
        _serviceCollection.AddTransient<App>();
    }
}

使用这种模式,每个lambda调用都将获得一个新的ServiceProvider并在完成后将其丢弃。

答案 3 :(得分:1)

如果您正在讨论针对WebAPI的AWS服务的依赖注入,则可以通过dotnet new lambda.AspNetCoreWebAPI或Visual Studio蓝图使用AspNetCoreWebAPI模板

此模板具有Startup类(当然,每个lambda环境都会执行一次启动,就像您提到的那样)。您在ConfigureServices

中添加了添加AWS服务
public void ConfigureServices(IServiceCollection services)
{
  services.AddMvc();
  services.AddDefaultAWSOptions(Configuration.GetAWSOptions());
  // Add service to obtain in Controllers constructor
  services.AddAWSService<IAmazonDynamoDB>();
}

然后使用构造函数为Controller类

进行依赖注入
IAmazonDynamoDB client;
public ValuesController(IAmazonDynamoDB dbClient)
{
    this.client = dbClient;
}

这些服务是从使用环境变量检索的凭据启动的,因此请确保将您的AWS配置文件包含在appsettings.json中。如果您不确定appsettings.json或如何根据ASPNETCORE_ENVIRONMENT声明配置文件发表评论。