简单的注入器 - 延迟初始化

时间:2017-06-08 13:59:49

标签: c# .net dependency-injection simple-injector

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

我有两项服务。

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服务在授权后返回UserCredentials个对象。 UserCredentials服务需要此GDrive。 这是一个简化的示例,但一般情况下,我需要在用户按申请表单上的GDrive按钮后使用正确的UserCredentials对象初始化Auth服务。

有没有办法做到这一点?

提前致谢。

1 个答案:

答案 0 :(得分:1)

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

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

我能想到你能做的两件事。您可以将IGAuth注入GDrive并确保在构造函数运行后调用它,或者注入构造函数运行后可以请求的惰性异步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时触发异步操作。