J'ai créé des fonctions Lambda avec AWS.Net SDK, version de base .net 1.0. Je veux implémenter l'injection de dépendance. Étant donné que les fonctions lambda sont déclenchées et exécutées indépendamment dans l'environnement AWS, il n'existe aucune classe telle que Startup
. Comment et où puis-je configurer mes conteneurs pour réaliser cette implémentation?
Tu peux le faire. Votre FunctionHandler est votre point d'entrée dans votre application. Vous devez donc câbler la collection de services à partir de celle-ci.
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";
}
}
Si vous souhaitez câbler la journalisation, regardez ici: https://github.com/aws/aws-lambda-dotnet/tree/master/Libraries/src/Amazon.Lambda.Logging.AspNetCore
Si vous parlez d'injection de dépendance de AWS Services for WebAPI, il est possible d'utiliser un modèle AspNetCoreWebAPI via dotnet new lambda.AspNetCoreWebAPI
ou des modèles Visual Studio.
Ce modèle a une classe de démarrage (bien sûr, chaque démarrage est exécuté une fois par environnement lambda, comme vous l’avez mentionné). Vous ajoutez des services AWS dans ConfigureServices
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDefaultAWSOptions(Configuration.GetAWSOptions());
// Add service to obtain in Controllers constructor
services.AddAWSService<IAmazonDynamoDB>();
}
Puis utilisez le constructeur pour l'injection de dépendance de votre classe de contrôleur
IAmazonDynamoDB client;
public ValuesController(IAmazonDynamoDB dbClient)
{
this.client = dbClient;
}
Ces services sont démarrés avec les informations d'identification extraites des variables d'environnement. Veillez donc à inclure votre profil AWS dans le fichier appsettings.json. Si vous n’êtes pas sûr de savoir sur appsettings.json ou sur la façon de déclarer des profils conformément à ASPNETCORE_ENVIRONMENT, laissez un commentaire.
Alors que FunctionHandler est bien votre point d’entrée dans votre application, je brancherais en réalité votre ID dans un constructeur sans paramètre. Le constructeur n’est appelé qu’une fois, aussi ce code purement "setup" ne devrait en réalité être appelé qu’une fois. Nous voulons simplement tirer parti de son utilisation lors de chaque appel ultérieur acheminé vers le même conteneur.
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;
}
}