Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async factory in Simple Injector

I'm configuring Quartz library for working with Simple Injector and I have problem with properly register it. The problem is that GetScheduler() is async and this code is registering Task<IScheduler> not IScheduler

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

How to register factory method in Simple Injector that is async? Of course i can wait for result using Result of Task but maybe there is other way?

like image 988
dnf Avatar asked Sep 24 '17 15:09

dnf


People also ask

What is the use of async method?

An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete. In the meantime, control returns to the caller of the method, as the example in the next section shows.

How does async improve performance?

With async/await your async operation doesn't need thread time, thus you give more time for other threads of your application to do job. For instance your application (non-UI) can still make HTTP calls, and all you need is just wait for the response. This is one of the cases when benefit of using async/await is big.

What is Simpleinjector?

Simple Injector is an easy-to-use Dependency Injection (DI) library for . NET that supports . NET Core, Xamarin, Mono and Universal apps. Simple Injector is easily integrated with frameworks such as Web API, MVC, WCF, ASP.NET Core and many others.


1 Answers

Although you can register and inject a Task<ISceduler>, Simple Injector does not support the registration of async factory methods, because its GetInstance methods are synchronous.

As a matter of fact, no DI Container supports this, and neither should they. Object Composition should be fast and reliable and no I/O operations should take place during object composition.

Having I/O (and thus async) operations run during Object Composition causes the operation to become slow, unreliable and makes it much harder to test object construction (since the external I/O resource must be available during that time).

Instead, async operations should be moved either before Object Composition or after Object Composition. Before Object Composition means during application startup, which means one-time start-up initialization, while async operations that happen after Object Composition are triggered by the calls made to components on the constructed object graph.

What the correct solution is in your case depends on several factors.

In case your application only needs one IScheduler in your application, it might be okay to call factory.GetScheduler once at application startup and register the IScheduler as Singleton in the container. Here's a related discussion about doing async start-up initialization.

If however the IScheduler can't be a singleton, this means that your code that uses IScheduler needs to become asynchronous (what it probably already is). It might mean you need to inject an ISchedulerFactory into components that need to use IScheduler. This way you can await the GetScheduler method.

Another common option is to create a Virtual Proxy implementation of the abstraction we are working with, in this case IScheduler. This however does not work in the case of Quartz because

  1. The IScheduler interface has many members and creating a Virtual Proxy for that is very cumbersome.
  2. It requires all members of IScheduler to be async, but there quite a few that aren't async, such as IsStarted. Creating an application-specific abstraction therefore makes much more sense.

This means to hide the use of IScheduler behind an asynchronous application-specific abstraction. This abstraction will hide the complexity of working with a scheduler and by making its methods asynchronous you can allow a scheduler to be created lazily by implementation of this new abstraction. This implementation will be an adapter that hides the complexity of the scheduler.

like image 161
Steven Avatar answered Oct 09 '22 21:10

Steven