web-dev-qa-db-ja.com

AWS Lambda C#実装で依存性注入を使用する方法

AWS.Net SDK、.net coreバージョン1.0を使用してLambda関数を作成しました。依存性注入を実装したい。ラムダ関数はAWS環境で独立してトリガーおよび実行されるため、Startupのようなクラスは存在しません。この実装を実現するためにコンテナをどこでどのように構成できますか?

16
Yaduraj

あなたはこれを行うことができます。 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 =

9
Donuts

私はゲームにかなり遅れていることを知っていますが、インターネットには悪い例や欠けている例があると思うので、これを追加します。 @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>();
    }
}

このパターンを使用すると、ラムダを呼び出すたびに新しいServiceProviderが取得され、終了時に破棄されます。

8
Chris Dargis

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;
    }
}
7
Tim Robinson

AWS Services for WebAPIの依存性注入について話している場合、dotnet new lambda.AspNetCoreWebAPIまたはVisual Studioブループリントを介してAspNetCoreWebAPIテンプレートを使用することが可能です。

このテンプレートにはスタートアップクラスがあります(もちろん、各スタートアップは、前述のようにラムダ環境ごとに1回実行されます)。 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に従ってプロファイルを宣言する方法がわからない場合は、コメントを残してください。

1
Can Sahin