In the Call asynchronous method in constructor? question is no answer that, starts the async Operation in the constructor and store the Task in a member and an awaits it before using the resource:
public class DeviceAccess
{
private readonly Task<Container> containerTask;
public DeviceAccess(Database database)
{
containerTask = GetContainer(database);
}
private async Task<Container> GetContainer(Database database)
{
var conatinerResponse = await database.CreateContainerIfNotExistsAsync("Device");
return conatinerResponse.Container;
}
public async Task<Device> GetDevice(string deviceId)
{
var container = await containerTask;
return await doSomething(container);
}
}
In my case every Operation needs the resource, so I see no advantage to use some lazy loading.
Is it valid to start a async Operation in a constructor or can result this into problems?
The biggest problem I can see here is that [Value]Task[<T>] is an API that enables async, not a promise to be async; just because CreateContainerIfNotExistsAsync is named *Async and returns Task<T> - that doesn't actually mean it is async - it could run synchronously and return a result via Task.FromResult (aka "async over sync"). If you're not concerned about that problem, then fine I guess. But I wonder whether an OpenAsync() method that you call after construction would be more appropriate, i.e.
public class DeviceAccess
{
private Container _container;
public DeviceAccess() {}
public async ValueTask OpenAsync(Database database) {
if (_container == null)
_container = await GetContainerAsync(database);
}
public async Task<Device> GetDeviceAsync(string deviceId)
{
var container = _container ?? throw new InvalidOperationException("not open");
return await doSomething(container); // might be able to inline the "await" here
}
}
Related
In program, we have:
var task1 = some task;
task1.start()
If mock the task result in unit test, the result is returned by mock mechanism immediately before calling the start(), and raise "Start may not be called on a task that has completed" exception.
How to address that issue and compose a valid unit test?
Paste a simplified sample code here for clarity, which produces the above exception:
namespace TestTaskStart
{
public class TestMethods : ITestMethods
{
public async Task<int> AlwaysReturnOne(int number)
{
return await Task.FromResult(1);
}
}
}
namespace TestTaskStart {
public class TestInvoker
{
private ITestMethods testMethods;
public TestInvoker(ITestMethods testMethods)
{
this.testMethods = testMethods;
}
public async Task<int> GetANumberWrapperTask(int number)
{
// just an exmple of one tasks to be called
var task = this.testMethods.AlwaysReturnOne(number);
task.Start();
Task.WaitAll(task);
return task.Result;
}
}
}
namespace TestTaskStart {
[TestClass]
public class UnitTests
{
ITestMethods numberGetter;
TestInvoker testInvoker;
[TestInitialize]
public void Setup()
{
this.numberGetter = Substitute.For<ITestMethods>();
this.testInvoker = new TestInvoker(this.numberGetter);
}
[TestMethod]
public void TestGetANumberWrapper()
{
this.MockAlwaysReturnOneResult();
var result = testInvoker.GetANumberWrapperTask(5).Result;
}
private void MockAlwaysReturnOneResult()
{
this.numberGetter.AlwaysReturnOne(Arg.Any<int>()).Returns(1);
}
}
}
The Task.Start method can only be called on "cold" tasks, in other words on tasks that have not been started yet. Such tasks can only be created with the Task constructor. Tasks created by invoking asynchronous methods implemented with the async keyword are "hot", in other words they are already started upon creation. From the docs:
Exceptions
InvalidOperationException
The Task is not in a valid state to be started. It may have already been started, executed, or canceled, or it may have been created in a manner that doesn't support direct scheduling.
This is also a good reading: A Tour of Task, Part 10: Promise Tasks
In my application I need to call a method before all the API request. If a specific condition met then I need to execute set of statements in that method.
In order to generalize this I created a helper class something like this.
public class CertificateValidator {
readonly IDependencyService _serviceLocator;
public CertificateValidator(IDependencyService serviceLocator) {
_serviceLocator = serviceLocator;
}
public async Task <T> TryExecuteWithCertificateValidationAsync <T> (Task <T> operation) {
var service = _serviceLocator.Get <IDeviceService> ();
if (service.CertificateValidationRequired()) {
// My Code.
}
T actualResult = await operation;
return actualResult;
}
}
And In my viewmodel I have done something like this.
public CertificateValidator ValidateCertificate => new CertificateValidator(_serviceLocator);
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync());
private async Task<RequestResult<Response>> MyMethodAsync()
{
// Some code
}
But when I implement like this the execution flow is
First MyMethodAsync() will be called.
And when it reaches the await method it the executes the
TryExecuteWithCertificateValidationAsync method and runs the remaining code there.
And then when it reaches T actualResult = await operation; return
actualResult; the control go back to MyMethodAsync() - await statement.
And my doubt here is,
I need to execute the TryExecuteWithCertificateValidationAsync completely and then followed by MyMethodAsync.
In short as I said early, I need to execute set of code before I call all my API calls. How I can achieve something similar using async an await.
Rather than passing a Task pass a function:
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<Task<T>> operation)
{
var service = _serviceLocator.Get<IDeviceService>();
if (service.CertificateValidationRequired())
{
// My Code.
}
T actualResult = await operation();
return actualResult;
}
var response = await ValidateCertificate
.TryExecuteWithCertificateValidationAsync(MyMethodAsync);
Update as per comment
If the method requires arguments, the types need to be prepended as additional generic arguments to Func:
private async Task<RequestResult<Response>> MyMethodAsync(int i)
{
// Some code
}
public async Task<T> TryExecuteWithCertificateValidationAsync<T>(Func<int, Task<T>> operation) // Add int as second generic argument
{
T actualResult = await operation(1); // Can now be called with an integer
return actualResult;
}
I'm trying to use the reactiveui test scheduler with an async method in a test.
The test hangs when the async call is awaited.
The root cause seems to be a command that's awaited in the async method.
[Fact]
public async Task Test()
=> await new TestScheduler().With(async scheduler =>
{
await SomeAsyncMethod();
// *** execution never gets here
Debugger.Break();
});
private async Task SomeAsyncMethod()
{
var command = ReactiveCommand.CreateFromTask(async () =>
{
await Task.Delay(100);
});
// *** this hangs
await command.Execute();
}
How can I do an async call in combination with the test scheduler that does not deadlock?
I'm using reactiveui 9.4.1
EDIT:
I've tried the WithAsync() method as suggested in Funks answer, but the behaviour is the same.
How can I do an async call in combination with the test scheduler?
In short
command.Execute() is a cold observable. You need to subscribe to it, instead of using await.
Given your interest in TestScheduler, I take it you want to test something involving time. However, from the When should I care about scheduling section:
threads created via "new Thread()" or "Task.Run" can't be controlled in a unit test.
So, if you want to check, for example, if your Task completes within 100ms, you're going to have to wait until the async method completes. To be sure, that's not the kind of test TestScheduler is meant for.
The somewhat longer version
The purpose of TestScheduler is to verify workflows by putting things in motion and verifying state at certain points in time. As we can only manipulate time on a TestScheduler, you'd typically prefer not to wait on real async code to complete, given there's no way to fast forward actual computations or I/O. Remember, it's about verifying workflows: vm.A has new value at 20ms, so vm.B should have new val at 120ms,...
So how can you test the SUT?
1\ You could mock the async method using scheduler.CreateColdObservable
public class ViewModelTests
{
[Fact]
public void Test()
{
string observed = "";
new TestScheduler().With(scheduler =>
{
var observable = scheduler.CreateColdObservable(
scheduler.OnNextAt(100, "Done"));
observable.Subscribe(value => observed = value);
Assert.Equal("", observed);
scheduler.AdvanceByMs(99);
Assert.Equal("", observed);
scheduler.AdvanceByMs(1);
Assert.Equal("Done", observed);
});
}
}
Here we basically replaced command.Execute() with var observable created on scheduler.
It's clear the example above is rather simple, but with several observables notifying each other this kind of test can provide valuable insights, as well as a safety net while refactoring.
Ref:
Answer by Paul Betts
Control Time with the TestScheduler
2\ You could reference the IScheduler explicitly
a) Using the schedulers provided by RxApp
public class MyViewModel : ReactiveObject
{
public string Observed { get; set; }
public MyViewModel()
{
Observed = "";
this.MyCommand = ReactiveCommand
.CreateFromTask(SomeAsyncMethod);
}
public ReactiveCommand<Unit, Unit> MyCommand { get; }
private async Task SomeAsyncMethod()
{
await RxApp.TaskpoolScheduler.Sleep(TimeSpan.FromMilliseconds(100));
Observed = "Done";
}
}
public class ViewModelTests
{
[Fact]
public void Test()
{
new TestScheduler().With(scheduler =>
{
var vm = new MyViewModel();
vm.MyCommand.Execute().Subscribe();
Assert.Equal("", vm.Observed);
scheduler.AdvanceByMs(99);
Assert.Equal("", vm.Observed);
scheduler.AdvanceByMs(1);
Assert.Equal("Done", vm.Observed);
});
}
}
Note
CreateFromTask creates a ReactiveCommand with asynchronous execution logic. There's no need to define the Test method as async or await the TestScheduler.
Within the With extension method's scope RxApp.TaskpoolScheduler = RxApp.MainThreadScheduler = the new TestScheduler().
b) Managing your own schedulers through constructor injection
public class MyViewModel : ReactiveObject
{
private readonly IScheduler _taskpoolScheduler;
public string Observed { get; set; }
public MyViewModel(IScheduler scheduler)
{
_taskpoolScheduler = scheduler;
Observed = "";
this.MyCommand = ReactiveCommand
.CreateFromTask(SomeAsyncMethod);
}
public ReactiveCommand<Unit, Unit> MyCommand { get; }
private async Task SomeAsyncMethod()
{
await _taskpoolScheduler.Sleep(TimeSpan.FromMilliseconds(100));
Observed = "Done";
}
}
public class ViewModelTests
{
[Fact]
public void Test()
{
new TestScheduler().With(scheduler =>
{
var vm = new MyViewModel(scheduler); ;
vm.MyCommand.Execute().Subscribe();
Assert.Equal("", vm.Observed);
scheduler.AdvanceByMs(99);
Assert.Equal("", vm.Observed);
scheduler.AdvanceByMs(0);
Assert.Equal("Done", vm.Observed);
});
}
}
Ref:
Kent Boogaert's Answer
Testing Rx code - ISchedulerProvider
Let's close ranks with another quote from Haacked:
Unfortunately, and this next point is important, the TestScheduler doesn’t extend into real life, so your shenanigans are limited to your asynchronous Reactive code. Thus, if you call Thread.Sleep(1000) in your test, that thread will really be blocked for a second. But as far as the test scheduler is concerned, no time has passed.
Have you tried to use ConfigureAwait(false) when calling nested method?
[Fact]
public async Task Test()
=> await new TestScheduler().With(async scheduler =>
{
// this hangs
await SomeAsyncMethod().ConfigureAwait(false);
// ***** execution will never get to here
Debugger.Break();
}
Please try using .ConfigureAwait(false) on all your async methods.
This will provide you non-blocking behavior.
[Fact]
public async Task Test()
=> await new TestScheduler().With(async scheduler =>
{
await SomeAsyncMethod().ConfigureAwait(false);
// *** execution never gets here
Debugger.Break();
}).ConfigureAwait(false);
private async Task SomeAsyncMethod()
{
var command = ReactiveCommand.CreateFromTask(async () =>
{
await Task.Delay(100).ConfigureAwait(false);
}).ConfigureAwait(false);
// *** this hangs
await command.Execute();
}
Another way to test whether the problem is related with ConfigureAwait is to port your project to Asp.Net Core and test it there.
Asp.net core does not need to use ConfigureAwait to prevent this blocking issue.
Check this for Reference
I would to call an asynchronous function in an Unity injection factory, like so...
Container.RegisterType<HttpClient>(new InjectionFactory(
async c => await Create()));
... but it says...
Error CS4010: Cannot convert async lambda expression to delegate type
'Func'. An async lambda expression may return
void, Task or Task, none of which are convertible to
'Func'.
Is there a way around this?
Register the factory as Task<HttpClient> using the DelegateInjectionFactory. Then you can await it after it is injected, in code that you control.
public static IUnityContainer CompositionRoot()
{
var container = new Unity.UnityContainer();
container.RegisterType<Application>();
container.RegisterType<Task<HttpClient>>
(
new DelegateInjectionFactory
(
new Func<Task<HttpClient>>
(
async () => await Create()
)
)
);
return container;
}
public static async Task<HttpClient> Create()
{
await Task.Delay(1); //Simulate doing something asynchronous
return new HttpClient();
}
Example of a class that would receive the injection:
public class Example
{
protected readonly Task<HttpClient> _client; //Injected
public Example(Task<HttpClient> client)
{
_client = client;
}
public async Task<string> Run()
{
var result = await (await _client).GetAsync("http://www.StackOverflow.com");
var text = await result.Content.ReadAsStringAsync();
return text;
}
}
Now Create() will be executed asynchronously, but is not awaited by the container (which isn't set up for that). Instead, it is awaited by your own code, in the class that consumes it, which you have control over.
Note: While this example demonstrates that it is possible, I would probably not do this in production code. It is more common to write a factory class, give it an async method, inject the factory class, and await the method in the class receiving the injection.
I often write code that has convenience methods which basically wrap other methods. Here's a simple example:
public class WithoutAsync
{
public static ReadOnlyCollection<Response> GetResponses(IEnumerable<Request> fromRequests)
{
var ret = new List<Response>();
foreach (Request r in fromRequests)
{
ret.Add(new Response());
}
return ret.AsReadOnly();
}
//convenience method
public static Response GetResponse(Request fromRequest)
{
return GetResponses(new Request[] {fromRequest})[0];
}
}
Now I want to await long-running operations but I can't quite figure out how to retrofit this methodology for use with TPL:
public class WithAsync
{
public static async Task<ReadOnlyCollection<Response>> GetResponses(IEnumerable<Request> fromRequests)
{
var awaitableResponses = new List<Task<Response>>();
foreach (Request r in fromRequests)
{
awaitableResponses.Add(Task.Run<Response>(async () =>
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}));
}
return new List<Response>(await Task.WhenAll(awaitableResponses)).AsReadOnly();
}
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return GetResponse(new Request[] { fromRequest });
}
}
The convenience method above obviously won't work because it's trying to return a Task<ReadOnlyCollection<Response>> when it really needs to return a Task<Response>.
This works:
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return new Task<Response>(new Func<Response>(() => GetResponse(new Request[] { fromRequest }).Result[0]));
}
but it seems really awkward, and more importantly, it blocks on .Result[0] which is potentially on a UI thread.
Is there any good way to accomplish what I'm trying to do?
You're trying to avoid making that "convenience method" async, but there's no reason to do that.
What you want is to call the other method, wait until there are responses and then get the first and only one. You can do that by making it async and using await:
async Task<Response> GetResponseAsync(Request fromRequest)
{
var responses = await GetResponsesAsync(new[] { fromRequest });
return responses.Single();
}
Although a better solution in this specific case is to switch things around and have the single GetResponse actually do that work of a single request, and have the multiple GetRsponses call it instead:
async Task<ReadOnlyCollection<Response>> GetResponsesAsync(IEnumerable<Request> fromRequests)
{
return (await Task.WhenAll(fromRequests.Select(GetResponse))).ToList().AsReadOnly();
}
async Task<Response> GetResponseAsync(Request fromRequest)
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}
Notes:
I know it's an example, but there's probably no reason to use Task.Run instead of a simple async call.
The convention is to name async methods with an "Async" suffix (i.e. GetResponseAsync).
I've also pluralized the name of the method that returns a collection.
I'm still sticking with I3arnon's answer because it's a well-written, informative answer, but I'd like to submit my own answer because I realized that I was almost there. Here's the async convenience method I was struggling to find:
//convenience method
public static async Task<Response> GetResponse(Request fromRequest)
{
return (await GetResponses(new Request[] { fromRequest }))[0];
}