How to call async method in Autofac registration? - c#

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

We ran into the same issue but found a different solution, I thought I'd share. You can wrap your async code within the Register method in a Task.Run and call .GetResult() or .Wait(). This will spawn a new context which ensures that any async code runs nicely within that context before being returned.
Sample taken from the other response snippet:
builder.Register(c =>
{
var bar= c.Resolve<IBar>();
var foo = new Foo(bar);
var resultTask = Task.Run(async () => {
return await foo.ComputeAsync();
});
return resultTask.GetResult();
})
.As<IFoo>()
.SingleInstance();

Related

How can you mock an Automatonymous Activity?

I'm trying to unit test my state machine and that it transitions to the states I expect when certain events are received. To do this I'm using the InMemoryTestHarness which enables me to create my state machine and then using the bus I can publish messages to it.
For the most part this is fine. However, there are a couple of examples where it then goes off and does an activity before it transitions state like this:
During(Submitted,
When(OnFlyCoolThingRequest)
.Activity(activitySelector => activitySelector.OfType<MakeItFlyActivity>()).TransitionTo(Flying));
At this point I don't want to test the activity and as it happens it appears that it seems to actually break the test (just hangs). My test is currently setup like this:
[Test]
public async Task CoolThingSagaShouldTransitionToFlyingStateOnFlyCoolThingRequestEvent()
{
var stateMachine = new CoolStateMachine();
var harness = new InMemoryTestHarness();
var saga = harness.StateMachineSaga<CoolThingSaga, CoolStateMachine>(new CoolStateMachine());
await harness.Start();
try
{
var coolThing = GetCoolThing();
// Create a CoolThing instance.
await harness.Bus.Publish(new CoolThingCreated(coolThing.Id));
var instanceIdSubmitted = await saga.Exists(coolThing.Id, state => state.Submitted);
// Publish a FlyCoolThingRequest event for the above instance.
await harness.Bus.Publish(new FlyCoolThingRequest(coolThing.Id, DateTime.UtcNow));
var instanceIdFlying = await saga.Exists(coolThing.Id, state => state.Flying);
Assert.That(instanceIdSubmitted.Value, Is.EqualTo(instanceIdFlying.Value), $"Instance id returned between the state of '{stateMachine.Submitted.Name}' and '{stateMachine.Flying.Name}' should be the same.");
Assert.That(instanceIdFlying, Is.Not.Null, $"A CoolThingSaga instance should have been created with Id {instanceIdFlying} and a be in the state of '{stateMachine.Flying}'.");
}
finally
{
await harness.Stop();
}
}
At the moment this type of test works for testing states that don't have activities associated with them. However, the tests seem to hang when an activity is involved. So how can I mock the activity so it doesn't actually try and perform that logic?
UPDATE
Looks like it fails to create the activity due to not being able to find a parameterless constructor. My activity is akin to this:
public sealed class MakeItFlyActivity : Activity<CoolThingSaga, FlyCoolThingRequest>
{
private readonly FlyingService _flyingService;
public MakeItFlyActivity(FlyingService flyingService)
{
_flyingService = flyingService;
}
public async Task Execute(BehaviorContext<CoolThingSaga, FlyCoolThingRequest> context, Behavior<CoolThingSaga, FlyCoolThingRequest> next)
{
await flyingService.MakeItFly(context.Instance.Details.Id);
await next.Execute(context);
}
public void Accept(StateMachineVisitor visitor) => visitor.Visit(this);
public async Task Faulted<TException>(BehaviorExceptionContext<CoolThingSaga, FlyCoolThingRequest, TException> context, Behavior<CoolThingSaga, FlyCoolThingRequest> next)
where TException : Exception => await next.Faulted(context);
public void Probe(ProbeContext context) => context.CreateScope(nameof(MakeItFlyActivity));
}
My setup is as follows:
private InMemoryTestHarness fHarness;
private StateMachineSagaTestHarness<CoolThingSaga, CoolStateMachine> fSaga;
private CoolStateMachine fStateMachine;
[OneTimeSetUp]
public async Task Setup()
{
var provider = new ServiceCollection()
.AddSingleton<ILoggerFactory>(p => new TestOutputLoggerFactory(true))
.AddMassTransitInMemoryTestHarness(cfg =>
{
cfg.AddSagaStateMachine<CoolStateMachine, CoolThingSaga>().InMemoryRepository();
cfg.AddSagaStateMachineTestHarness<CoolStateMachine, CoolThingSaga>();
})
.AddSingleton(p => new FlyingService(TimeSpan.FromMinutes(15), NullLogger<FlyingService>.Instance))
.AddScoped<MakeItFlyActivity>()
.BuildServiceProvider(true);
fHarness = provider.GetRequiredService<InMemoryTestHarness>();
fSaga = fHarness.StateMachineSaga<CoolThingSaga, CoolStateMachine>(new CoolStateMachine());
fStateMachine = provider.GetRequiredService<CoolStateMachine>();
await fHarness.Start();
}
To test state machines, you should be using the container based test harness as outlined in the documentation. This will ensure that activities and their dependencies can be resolved at runtime. Your test likely hangs because the activity could not be created.
The documentation for v8 is linked, you can also refer to the v7 documentation if you're using an earlier version.

Issue when upgrading Autofac with async tasks and owned instances

I have an issue with Autofac after upgrading from 4.9.2 to 5.2 in my ASP.NET MVC application.
I make use of Func<Owned<T>> factory pattern in the Controller because an Controller Action starts a Long running Task and will run longer than the request exists. In that Task I am resolving other instances.
This worked fine in Autofac 4.9.2. But after upgrading to Autofac 5.2 the parent Lifetime scope (AutofacWebRequest) gets disposed and it not possible to resolve instances within the owned instance anymore.
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it (or one of its parent scopes) has already been disposed.
Is there something I can do to work around this or is there a best practice?
Controller Code:
private readonly Func<Owned<IBusinessLogic>> _businessLogicFactory;
public ActionResult Index()
{
var businessLogic = _businessLogicFactory();
var unitOfWorkFactory = _unitOfWorkFactory;
Task.Run(() =>
{
System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
using (businessLogic)
{
var task = businessLogic.Value.DoHardBusinessAsync();
task.Wait();
}
});
return View();
}
Business Logic Code (also using a factory):
public class BusinessLogic : IBusinessLogic
{
private readonly Func<Owned<OtherBusinessLogic>> _otherBusinessLogicFactory;
public BusinessLogic(Func<Owned<OtherBusinessLogic>> otherBusinessLogicFactory)
{
_otherBusinessLogicFactory = otherBusinessLogicFactory;
}
public async Task DoHardBusinessAsync()
{
using (var otherBusiness = _otherBusinessLogicFactory())
{
await otherBusiness.Value.DoHardBusinessAsync();
}
}
}
You could try to create a new lifetime scope that is independent of the request scope to be used with your long running task like so
Task.Run(() =>
{
using (var scope = container.BeginLifetimeScope())
{
System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
using (businessLogic)
{
var task = businessLogic.Value.DoHardBusinessAsync();
task.Wait();
}
}
});
Look at this question for ideas on how to get a hold of the container
Retrieving Autofac container to resolve services
#NataliaMuray's approach is awesome - one downside of it is that it tends to encourage Service Locator style resolving rather than constructor injection. This can tend to "hide" dependencies, making it harder to identify the dependencies of a given class.
One potential solution is to introduce the notion of a dependency that is explicit that it wraps another dependency that you want to resolve outside the normal web request's lifetime scope.
The code might look something like:
public class AsyncRunner : IAsyncRunner
{
public ExecutionResult TryExecute<TService>(Action<TService> toEvaluate, string #exceptionErrorMessage, int timeoutMilliseconds, string additionalErrorInformation = "")
{
try
{
var task = new Task(() =>
{
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<TService>();
toEvaluate(service);
}
});
task.ContinueWith(t => { /* logging here */, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously).SuppressExceptions();
task.Start();
var completedWithinTime = task.Wait(timeoutMilliseconds);
return completedWithinTime ? ExecutionResult.Ok : ExecutionResult.TimedOut;
}
catch (Exception e)
{
/* logging here */
return ExecutionResult.ThrewException;
}
}
}
Register IAsyncRunner with Autofac as well.
And then your dependency, instead of
private readonly Func<Owned<IBusinessLogic>> _businessLogicFactory;
would be
private readonly IAsyncRunner<IBusinessLogic>> _businessLogic;
And instead of:
var businessLogic = _businessLogicFactory();
var unitOfWorkFactory = _unitOfWorkFactory;
Task.Run(() =>
{
System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
using (businessLogic)
{
var task = businessLogic.Value.DoHardBusinessAsync();
task.Wait();
}
});
would be:
//var businessLogic = _businessLogicFactory();
var unitOfWorkFactory = _unitOfWorkFactory;
Task.Run(() =>
{
System.Threading.Thread.Sleep(5000); // Sleep simulates that it may take some time until other instances are resolved
_businessLogic.TryExecute(z => {
var task = z.Value.DoHardBusinessAsync();
task.Wait();
});
});
The advantage of this style is that the property and constructor injection makes clear what the dependencies are, and how they are being used (i.e. the declaration makes clear that it will be resolved outside the context of the standard lifetime scope). Note you don't need to use Owned with my suggestion (disposal of the lifetime scope that is manually constructed will be sufficient). I have removed the use of Func, but you could use Func or Lazy if you really needed it alongside my suggestion.

Test method with async await inside a task

I have a this code
public class ClassToTest
{
private readonly IRepository repository;
public ClassToTest(DI GOES HERE){...}
public DoSomething()
{
Task.Run(async () => {
//some code
repository.ExecuteAsync();
}
}
}
public class Repository : IRepository
{
public Task ExecuteAsync()
{
using (var connection = new SqlConnection(DbConfiguration.DatabaseConnection))
{
return connection.ExecuteAsync(storedProcedure, parameters, commandType: CommandType.StoredProcedure, commandTimeout: Configuration.TransactionTimeout);
}
}
}
[Test]
public void TestMethod()
{
var repository = new Mock<IRepository>;
var classToTest = new ClassToTest();
classToTest.DoSomething();
repository.Veryfy(p => p.ExecuteAsync(), Times.Once());
}
The test fails with this message
Expected invocation on the mock once, but was 0 times: p => p.ExecuteAsync()
Does anyone knows why?
Thanks
As others have alluded, because you're calling Task.Run and not waiting for a response, the Unit test will likely complete before the background task is even started, hence the Moq Verify failure.
Also, your code won't compile as is - when asking a Q on StackOverflow, be sure to give a complete, compilable MVP.
Of special importance is the bug in the code you are trying to test. Repository.ExecuteAsync calls connection.ExecuteAsync, inside a using scope, but this isn't awaited. This will mean that the connection will be disposed before the task completes. You'll need to change the method to async and await the call to defer disposal of the connection.
The wrapper method DoSomething method shouldn't use Task.Run(), although, because it adds no value to the repository Task, it doesn't need to repeat the async / return await, either.
The caller (your Unit test, in this instance) can then await DoSomething (or if the caller genuinely wants to do further processing without awaiting the Task, then leave it to the caller to decide. At least this way, the caller gets a handle to the Task, to check on completion).
The final state of your code might look more like this:
public class ClassToTest
{
private readonly IRepository _repository;
public ClassToTest(IRepository repository)
{
_repository = repository;
}
// Doesn't necessarily need to be async
public Task DoSomething()
{
// We're return the wrapped task directly, and adding no additional value.
return repository.ExecuteAsync();
}
}
public class Repository : IRepository
{
public async Task ExecuteAsync()
{
using (var connection = new SqlConnection(DbConfiguration.DatabaseConnection))
{
// Here we do need to await, otherwise we'll dispose the connection
return await connection.ExecuteAsync(storedProcedure, parameters,
commandType: CommandType.StoredProcedure,
commandTimeout: Configuration.TransactionTimeout);
}
}
}
// NUnit has full support for async / await
[Test]
public async Task TestMethod()
{
var repository = new Mock<IRepository>();
var classToTest = new ClassToTest(repository.Object);
repository.Setup(_ => _.ExecuteAsync()).Returns(Task.FromResult((object)null));
// Moq also has support for async, e.g. .ReturnsAsync
// You need to await the test.
await classToTest.DoSomething();
repository.Verify(p => p.ExecuteAsync(), Times.Once());
}

How to use Microsoft Fakes to Shim Async Task method?

I'm using Microsoft Fakes to Shim an async method that invokes another method to get an implemented DbContext. Because database connection string is not supplied in the Unit Test while the method being invoked inside the async method needs it. Shim will not only skip the method that uses the connection string, but returns a customizable DbContext.
Here is the aysnc method implementation:
public async Task<AccountDataDataContext> GetAccountDataInstance(int accountId)
{
var account = await this.Accounts.FindAsync(accountId);
return AccountDataDataContext.GetInstance(account.AccountDataConnectionString);
}
However, I'm not familiar with Shim async method. What I did look like this:
ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 = (x, y, z) => new Task<AccountDataEntities.AccountDataDataContext>(() =>
{
return new SampleContext();// This is the fake context I created for replacing the AccountDataDataContext.
});
And SampleContext is implementing AccountDataDataContext as follows:
public class SampleContext: AccountDataDataContext
{
public SampleContext()
{
this.Samples = new TestDbSet<Sample>();
var data = new AccountDataRepository();
foreach (var item in data.GetFakeSamples())
{
this.Samples.Add(item);
}
}
}
Below is the code snippet for the test case:
[TestMethod]
public async Task SampleTest()
{
using (ShimsContext.Create())
{
//Arrange
SamplesController controller = ArrangeHelper(1);// This invokes the Shim code pasted in the second block and returns SamplesController object in this test class
var accountId = 1;
var serviceId = 2;
//Act
var response = await controller.GetSamples(accountId, serviceId);// The async method is invoked in the GetSamples(int32, int32) method.
var result = response.ToList();
//Assert
Assert.AreEqual(1, result.Count);
Assert.AreEqual("body 2", result[0].Body);
}
}
As the result, my test case is running forever. I think I might write the Shim lamdas expression completely wrong.
Any suggestion? Thank you.
You don't want to return a new Task. In fact, you should never, ever use the Task constructor. As I describe on my blog, it has no valid use cases at all.
Instead, use Task.FromResult:
ConfigurationEntities.Fakes.ShimConfigurationDataContext.AllInstances.GetAccountDataInstanceInt32NullableOfInt32 =
(x, y, z) => Task.FromResult(new SampleContext());
Task also has several other From* methods that are useful for unit testing (e.g., Task.FromException).

How to call some async code in an ASP.NET application_start

In our application_startup, we seed up our database with some fake data, if no data exists.
To do this, we're using the Async methods to store the data. Great. Only problem is, we're not sure how to do this in the application_startup because that's not an async method.
I've spent soooo much time trying to understand #StevenCleary's tutorials and I'm always getting deadlocks. I totally grok what he consistently says:
As a general rule, you should use "async all the way down"; that is, don't block on async code
but I just don't get how I can do that, in this case :(
Lets imagine this is the code I'm trying to play with...
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
await documentStore.InitializeAsync(someFakeData);
...
// Registers this database as a singleton.
Container.Register(documentStore);
}
and later on .. some code that uses this documentStore. It is injected via construction injection ...
public SomeController(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public ViewModel GetFoos()
{
using (var session = _documentStore.OpenSession())
{
... db code goes in here ...
}
}
Clarification
I'm not trying to do some async code in here. I'm actually trying to call this async method, synchronously. Sure, i loose the benefits of async blah blah de blah.. but i'm happy with that. This is start up and I'm happy to block on startup.
In this case, you're asynchronously initializing a shared resource. So, I recommend that you either save the Task itself, or introduce an asynchronous wrapper type.
Using Task:
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
var documentStoreTask = documentStore.InitializeAsync(someFakeData);
...
// Registers this database task as a singleton.
Container.Register(documentStoreTask);
}
That may be too awkward, though, depending on Container. In that case, you can introduce an asynchronous wrapper type:
public sealed class DocumentStoreWrapper
{
private readonly Task<DocumentStore> _documentStore;
public DocumentStoreWrapper(Data data)
{
_documentStore = CreateDocumentStoreAsync(data);
}
private static async Task<DocumentStore> CreateDocumentStoreAsync(Data data)
{
var result = new DocumentStore();
await documentStore.InitializeAsync(data);
...
return result;
}
public Task<DocumentStore> DocumentStoreTask { get { return _documentStore; } }
}
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStoreWrapper = new DocumentStoreWrapper(someFakeData);
...
// Registers this database wrapper as a singleton.
Container.Register(documentStoreWrapper);
}
Or, you could use AsyncLazy<T>, which does much the same thing but uses a background thread to execute the initialization code.
You can use of Task.Run(() => YourAsyncMethod()); inside of none async method like:
protected void Application_Start()
{
Task.Run(() => MyAsyncMethod(true));
}
This is an old topic, but it's popped up in my search and maybe it will for others.
For what the OP has requested (ie. To run an async method in a synchronous way from inside a synchronous method, and block until it's finished), is there some reason that the use of Task.WaitAll would not be a simple and adequate way of addressing this?
protected void Application_Start()
{
Task.WaitAll(MyAsyncMethod(true));
}
public static class AsyncHelper
{
private static readonly TaskFactory MyTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
then use as
AsyncHelper.RunSync(ProcessAsync);
private async Task ProcessAsync(){ ....

Categories