Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async tasks and Simple Injector Lifetime scopes

I've got the following method which resolves an IConsumeAsync which returns a task.

private Task ConsumeMessageAsync<TMessage, TConsumer>(TMessage message)
    where TMessage : class
    where TConsumer : IConsumeAsync<TMessage>
{
    var tsc = new TaskCompletionSource<object>();
    var instance = (IConsumeAsync<TMessage>)container
        .GetInstance(typeof(TConsumer));

    instance
        .Consume(message)
        .ContinueWith(task =>
        {
            if (task.IsFaulted && task.Exception != null)
            {
                tsc.SetException(task.Exception);
            }
            else
            {
                tsc.SetResult(null);
            }
        });

    return tsc.Task;
}

I need to wrap this with a lifetime scope ala

using(var scope = container.BeginLifetimeScope()){
}

I've tried the following but it did not work 100%

var scope = container.BeginLifetimeScope();

var wrapper = ConsumeMessageAsync<TMessage, TConsumer>(message);
wrapper.ContinueWith(x => scope.Dispose());
wrapper.Start();

And I got the following error:

Additional information: It is not safe to use a LifetimeScope instance across threads. Make sure the complete operation that the lifetime scope surrounds gets executed within the same thread and make sure that the LifetimeScope instance gets disposed on the same thread as it gets created. Dispose was called on thread with ManagedThreadId 27, but was created on thread with id 21.

I'm not quite sure how to wrap an asynchronous task in .NET with using statements to tried a manual kind using an extra wrapper task to control the flow.

like image 235
Michael Carr Avatar asked Jul 10 '15 15:07

Michael Carr


1 Answers

You need to use the AsyncScopedLifestyle instead. The ThreadScopedLifestyle (previously called LifetimeScopeLifestyle) creates a thread-specific scope, while the AsyncScopedLifestyle creates a scope that flows with the logical flow of control of asynchronous methods.

// using SimpleInjector.Lifestyles;

using (AsyncScopedLifestyle.BeginScope(container)) {
    var service = container.GetInstance<ISomeService>();
    // ...
}
like image 194
Steven Avatar answered Oct 01 '22 13:10

Steven