I want to do call an awaitable async method during a registration like this:
// builder variable contains Autofac ContainerBuilder
builder.Register(
(async (context, parameters) => // need async here
{
var someClass = new SomeClass(context.Resolve<ISomeDependency>());
await someClass.SomeAsyncInitMethod(); // need to await result
return someClass;
})).As<ISomeClass>().SingleInstance();
SomeClass implements ISomeClass as Service.
The important part is the someClass.SomeAsyncInitMethod() call. This is async, so because of this I need to await it here and put the async keyword into the Register method. But now Autofac thinks this returns a Task<SomeClass> which is not registerable as Service ISomeClass.
How to achieve the above and register SomeClass as ISomeClass when awaiting the async init Method?
I think that doing any I/O intensive work at resolution phase is wrong design, because it's usually important to have full control over the order of this operations, catch their exceptions, repeat them, control time between some of them, etc.
Solution is to postpone them with factories. Let me replace SomeClass with a more meaningful NpgsqlConnection:
var builder = new ContainerBuilder();
builder.Register(context =>
{
// make sure not to capture temporary context:
// https://autofaccn.readthedocs.io/en/latest/advanced/concurrency.html#service-resolution
var connectionString = context.Resolve<IConfiguration>().GetConnectionString("MyDb");
return new Func<Task<NpgsqlConnection>>(async () =>
{
var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();
return connection;
});
});
And here's how connection user can look like:
public sealed class Repository
{
private readonly Func<Task<NpgsqlConnection>> _connectionFactory;
public Repository(Func<Task<NpgsqlConnection>> connectionFactory)
{
_connectionFactory = connectionFactory;
}
public async Task<string> GetServerVersionAsync()
{
using (var openedConnection = await _connectionFactory())
return openedConnection.ServerVersion;
}
}
Even if Autofac would support async registrations, it is still would be beneficial to require a factory in Repository constructor, because the connection is a limited resource and it is better to limit the time it is opened.
This is an old question, but I think autofac does not support that.
We used:
builder.Register(c =>
{
var bar= c.Resolve<IBar>();
var foo = new Foo(bar);
return foo.ComputeAsync().ConfigureAwait(false).GetAwaiter().GetResult();
})
.As<IFoo>()
.SingleInstance();
But as mentioned on the comments: Registering async factory in Autofac
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