简单注入器 - 延迟初始化
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
授权后的对象。而 UserCredentials
是 GDrive
服务所必需的。
这是一个简化的示例,但通常我需要在用户按下申请表上的 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
时触发异步操作。
有人可以帮我解答一个问题吗?
我有两个服务。
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
授权后的对象。而 UserCredentials
是 GDrive
服务所必需的。
这是一个简化的示例,但通常我需要在用户按下申请表上的 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
时触发异步操作。