简单注入器 - 延迟初始化

Simple Injector - Delayed Initialization

有人可以帮我解答一个问题吗?

我有两个服务。

GAuth:

public class GAuth : IGAuth
{
    public async Task<UserCredential> AuthorizeAsync(ClientSecrets clientSecrets)
    {
        using (var cts = new CancellationTokenSource())
        {
            var localServerCodeReceiver = new LocalServerCodeReceiver();

            cts.CancelAfter(TimeSpan.FromMinutes(1));

            return await GoogleWebAuthorizationBroker.AuthorizeAsync(
                clientSecrets,
                _scopes,
                User,
                cts.Token,
                new FileDataStore(string.Empty), localServerCodeReceiver
            );
        }
    }
}

GDrive:

public class GDrive : IGDrive
{
    private readonly DriveService _driveService;

    public GDrive(UserCredential userCredential)
    {
        _driveService = new DriveService(new BaseClientService.Initializer
        {
            HttpClientInitializer = userCredential,
            ApplicationName = string.Empty
        });
    }
}

以及注册部分:

container.Register<IGAuth, GAuth>(Lifestyle.Singleton);
container.Register<IGDrive, GDrive>(Lifestyle.Singleton);

如你所见GAuth服务returnsUserCredentials授权后的对象。而 UserCredentialsGDrive 服务所必需的。 这是一个简化的示例,但通常我需要在用户按下申请表上的 Auth 按钮后使用正确的 UserCredentials 对象初始化 GDrive 服务。

有什么办法吗?

提前致谢。

从设计的角度来看,注入构造函数应该是simple, fast and reliable。您的情况并非如此,因为对象图的构建取决于 I/O.

相反,您应该将 IO 推迟到构造函数具有 运行 之后。

我想到您可以做两件事。要么将 IGAuth 注入 GDrive 并确保在构造函数具有 运行 之后调用它,要么注入可以在构造函数具有 [=36] 之后请求的惰性异步 UserCredential =].

这是后者的一个例子:

public class GDrive : IGDrive
{
    private readonly Lazy<Task<DriveService>> _driveService;

    public GDrive(Lazy<Task<UserCredential>> userCredential)
    {
        _driveService = new Lazy<Task<DriveService>>(async () =>
            new DriveService(new BaseClientService.Initializer
            {
                HttpClientInitializer = await userCredential.Value,
                ApplicationName = string.Empty
            }));
    }

    public async Task SomeMethod()
    {
        var service = await _driveService.Value;

        service.DoSomeStuff();
    }
}

您可以按如下方式配置此 GDrive

var auth = new GAuth();
var credentials = new Lazy<Task<UserCredential>>(
    () => auth.AuthorizeAsync(new ClientSecrets()));

container.RegisterSingleton<IGDrive>(new GDrive(credentials));

另一种选择是将 GAuth 注入 GDrive。这将导致如下结果:

public class GDrive : IGDrive
{
    private readonly Lazy<Task<DriveService>> _driveService;

    public GDrive(IGAuth auth)
    {
        _driveService = new Lazy<Task<DriveService>>(async () =>
            new DriveService(new BaseClientService.Initializer
            {
                HttpClientInitializer = await auth.AuthorizeAsync(new ClientSecrets()),
                ApplicationName = string.Empty
            }));
    }

    public async Task SomeMethod()
    {
        var service = await _driveService.Value;

        service.DoSomeStuff();
    }
}

请注意,在这两种情况下都会创建一个 Lazy<Async<T>>,以确保仅在首次调用 Lazy<T>.Value 时触发异步操作。