【发布时间】:2018-06-01 23:11:47
【问题描述】:
我使用 AWS.Net SDK、.net 核心版本 1.0 创建了 Lambda 函数。我想实现依赖注入。由于 lambda 函数在 AWS 环境中触发并独立运行,因此不存在像 Startup 这样的类。我如何以及在哪里配置我的容器来实现这个实现?
【问题讨论】:
-
老实说,我认为这是不可能的。但我可能是错的。
标签: c# .net-core aws-lambda
我使用 AWS.Net SDK、.net 核心版本 1.0 创建了 Lambda 函数。我想实现依赖注入。由于 lambda 函数在 AWS 环境中触发并独立运行,因此不存在像 Startup 这样的类。我如何以及在哪里配置我的容器来实现这个实现?
【问题讨论】:
标签: c# .net-core aws-lambda
我知道我迟到了,但我添加了这个,因为我相信互联网上有一些不好/缺乏的例子。 @Erndob 对已接受的答案是正确的。您只会创建更多实例。
根据您在 DI 容器中进行的注册,您需要牢记:
最后是这样的:
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,并在完成时将其丢弃。
【讨论】:
ServiceCollection?
ServiceCollection。
虽然 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;
}
}
【讨论】:
FunctionHandler 应该以:` using var scope = ServiceProvider.CreateScope(); 开头scope.ServiceProvider.GetRequiredService你可以这样做。您的 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
【讨论】:
serviceCollection.BuildServiceProvider().GetService<App>().Run()