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?
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.
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.
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.
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
IScheduler
interface has many members and creating a Virtual Proxy for that is very cumbersome. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With