.net 依赖于具有异步解析方法的工厂的DI仓库

e5nszbig  于 2022-11-19  发布在  .NET
关注(0)|答案(1)|浏览(123)

我有一个UserRepository,它依赖于IDynamoDbClientFactory。问题是IDynamoDbClientFactory有一个方法,而且是异步的。ServiceCollections DI框架不允许我有一个异步提供程序。我不允许更改DynamoDbClientFactory,因为它在外部库中。
我如何以比下面使用.GetAwaiter().GetResult()所做的更好的方式处理这个问题?

services.AddSingleton<IDynamoDbClientFactory, DynamoDbClientFactory>();

services.AddSingleton<IUserRepository>(provider =>
{
    var dbClientFactory = provider.GetRequiredService<IDynamoDbClientFactory>();
    var dynamoDb = dbClientFactory.GetClientAsync().GetAwaiter().GetResult();
    return new UserRepository(dynamoDb);
});

我找到了this similar question,它建议使用适配器来隐藏应用程序代码中的异步操作。
为了简单起见,我删除了不重要的代码。
第一次
以下是未使用的。

// The adapter hides the details about GetClientAsync from the application code.
// It wraps the creation and connection of `MyClient` in a `Lazy<T>`,
// which allows the client to be connected just once, independently of in which order the `GetClientAsync`
// method is called, and how many times.
public class DynamoDbClientAdapter : IDisposable
{
    private readonly Lazy<Task<IDynamoDbClientFactory>> _factories;

    public DynamoDbClientAdapter(IConfiguration configuration)
    {
        _factories = new Lazy<Task<IDynamoDbClientFactory>>(async () =>
        {
            var client = new DynamoDbClientFactory(configuration);
            await client.GetClientAsync();
            return client;
        });
    }

    public void Dispose()
    {
        if (_factories.IsValueCreated)
        {
            _factories.Value.Dispose();
        }
    }
}
ygya80vv

ygya80vv1#

请尝试以下操作:

services.AddSingleton<IDynamoDbClientFactory, DynamoDbClientFactory>();
services.AddScoped<IUserRepository, DynamicClientUserRepositoryAdapter>();

其中DynamicClientUserRepositoryAdapterComposition Root中的一个适配器,它根据所需的IAmazonDynamoDB按需创建真实的的UserRepository

public class DynamicClientUserRepositoryAdapter : IUserRepository
{
    private readonly IDynamoDbClientFactory factory;
    private IUserRepository repository;

    public DynamicClientUserRepositoryAdapter(IDynamoDbClientFactory factory) =>
        this.factory = factory;

    private async Task<IUserRepository> GetRepositoryAsync()
    {
        if (this.repository is null)
        {
            var client = await this.factory.GetClientAsync();
            this.repository = new UserRepository(client);
        }
        
        return this.repository;
    }
    
    public async Task<UserDto?> GetAsync(string hashKey, string sortKey)
    {
        var repository = await this.GetRepositoryAsync();
        return await repository.GetAsync(hashKey, sortKey);
    }

    public async Task<bool> CreateAsync(UserDto userDto)
    {
        var repository = await this.GetRepositoryAsync();
        return await repository.CreateAsync(userDto);
    }

    public async Task<bool> UpdateAsync(UserDto userDto)
    {
        var repository = await this.GetRepositoryAsync();
        return await repository.UpdateAsync(userDto);
    }

    public async Task<bool> DeleteAsync(string hashKey, string sortKey)
    {
        var repository = await this.GetRepositoryAsync();
        return await repository.DeleteAsync(hashKey, sortKey);
    }
}

注意:我假设IAmazonDynamoDB不是线程安全的,这就是我将DynamicClientUserRepositoryAdapter注册为作用域的原因。
为什么要设计这样的东西的理由在the answer中解释,你已经在你的问题中提到了。

相关问题