Simple Injector中的异步工厂

时间:2017-09-24 15:49:16

标签: c# async-await factory quartz.net simple-injector

我正在配置Quartz库以使用Simple Injector,我有正确注册它的问题。问题是GetScheduler()是异步的,而且此代码正在注册Task<IScheduler>而不是IScheduler

 container.Register(async () =>
 {
      return await container.GetInstance<ISchedulerFactory>().GetScheduler();
 });

如何在Simple Injector中注册异步的工厂方法?当然我可以使用Result的{​​{1}}等待结果,但也许还有其他方式?

1 个答案:

答案 0 :(得分:6)

虽然您可以注册并注入Task<ISceduler>,但Simple Injector不支持异步工厂方法的注册,因为它的GetInstance方法是同步的。

事实上,没有DI Container支持这一点,也不应该支持。对象组合应为fast and reliable,并且在对象组合期间不应执行I / O操作。

在对象组合期间运行I / O(以及因此异步)操作会导致操作变得缓慢,不可靠并使测试对象构造变得更加困难(因为在此期间外部I / O资源必须可用)。

相反,应在Object Composition之前或Object Composition之后移动异步操作。在对象组合之前意味着在应用程序启动期间,这意味着一次性启动初始化,而在对象组合之后发生的异步操作由对构造的对象图上的组件的调用触发。

在您的情况下,正确的解决方案取决于几个因素。

如果您的应用程序在您的应用程序中只需要一个IScheduler,则可以在应用程序启动时调用factory.GetScheduler一次并将IScheduler注册为Singleton容器。 Here's a related discussion关于执行异步启动初始化。

但是,如果IScheduler不能成为单身,这意味着使用IScheduler的代码需要变为异步(它可能已经是异步)。这可能意味着您需要将ISchedulerFactory注入需要使用IScheduler的组件。这样您就可以等待GetScheduler方法。

另一个常见选项是创建我们正在使用的抽象的虚拟代理实现,在本例中为IScheduler。然而,这在Quartz的情况下不起作用,因为

  1. IScheduler接口有很多成员,为此创建虚拟代理非常麻烦。
  2. 它要求IScheduler的所有成员都是异步的,但有很多不是异步的,例如IsStarted。因此,创建特定于应用程序的抽象更有意义。
  3. 这意味着隐藏异步应用程序特定抽象背后IScheduler的使用。这种抽象将隐藏使用调度程序的复杂性,并通过使其方法异步,您可以通过实现这种新抽象来懒惰地创建调度程序。此实现将是一个隐藏调度程序复杂性的适配器。