How to await a Task inside of a test method - c#

In my repository's unit test project, I'm creating a cleanup method to delete all of the records that were created by tests. Here is what I'm trying to do:
private void DeleteTestExtensions()
{
var authorization = _extensionRepository.GetAuthorizationByTaxAccountIdAndYear(_testTaxAccountId, _testTaxAccountYear);
var extensions = await _extensionRepository.GetExtensionsByUserIdAsync(_testUserId);
foreach (var extension in extensions)
{
try
{
_extensionRepository.DeleteExtension(extension.ExtensionID);
}
}
_extensionRepository.DeleteAuthorization(authorization.ExtensionAuthorizationID);
}
The first one is synchronous and works as expected, but the second method is asynchronous and tells me the await operator can only be used on an async method, but whenever I hover over GetExtensionsByUserIdAsync, I can see (plus I know) that it's defined as
(awaitable) Task<List<Extension>> IExtensionRepository.GetExtensionsByUserIdAsync(Guid userID)
So why would it tell me that I can't use await when it's clearly async?

The message is actually relating to DeleteTestExtensions which must be marked as async, not GetExtensionsByUserIdAsync.
So your method signature would become:
private async Task DeleteTestExtensions()
Note marking the method as returning Task means it can in turn be awaited.

Related

Guidance needed with Task and async await [duplicate]

This question already has an answer here:
EF6 two contexts vs. single context with two awaits
(1 answer)
Closed 4 years ago.
After going through a lot of articles and videos i am still having problem with the asynchronous programming.I am working on a project where in service layer I have created all the methods as async. All of the return Task <T> or Task (I made sure not to return void).
Now to the issue. My Api calls async methods which internally calls other async methods which may even call other async methods. So I await every time I encounter an async method.
The downside with this approach, I think, is that cause I am awaiting for result every time I encounter async it will take a lot of time. For ex:
public async Task<xyz> DoMainTask(int ActionId, int ItemId, int UserId)
{
await DoTask1(ActionId,ItemId,UserId); 3 sec
await DoTask2(ActionId,ItemId,UserId); 3 sec
await DoTask3(ActionId,ItemId,UserId); 3 sec
}
So I don't want to wait for 9 sec because all tasks here are independent of each other.
I want to do something like:
public async Task<xyz> DoMainTask(int ActionId, int ItemId, int UserId)
{
List<Task> lst = new List<Task>();
t1= DoTask1(ActionId,ItemId,UserId);
lst.Add(t1);
t2 = DoTask2(ActionId,ItemId,UserId);
lst.Add(t2);
t3 = DoTask3(ActionId,ItemId,UserId);
lst.Add(t3);
await Task.WhenAll(lst);
// do some work
return xyz;
}
Which will probably take around 5-6 sec. How do I do this?
Whenever I try to use 2nd approach it get error:
A second operation started on this context before a previous asynchronous operation completed
DoTask1 is defined as:
public async Task DoTask1 (int ActionId, int ItemId, int UserId)
{
try
{
DailyActivityPoint dailyActivityPoint = new DailyActivityPoint()
{
ActionId = ActionId,
CreatedDate = DateTime.Now,
ItemId = ItemId,
UserId = UserId,
PointsAccumulated = await GetPointsAwardedForAction(ActionId)
};
_entities.DailyActivityPoints.Add(dailyActivityPoint);
await _entities.SaveChangesAsync();
}
catch (Exception ex)
{
}
}
inside DoTask1 I am also calling an async method.
How can it be done and what's the best practice?
I believe you are encountering a thread-safety concern as described here. If so, you'll need to be sure that for each 'awaitable' that reaches into EF it is using its own DbContext instance.
So, be sure you aren't using a DbContext singleton; instantiate a new one as you go if you can or get tricky with a container like he does in the link (containers are your friends)
Maybe you should use this guideline in writing your asynchronous methods
Guideline:
Write the method the normal way you would write a conventional method, then convert it to an async method.
Use the async keyword in the method declaration.
public async Task<int> ExampleMethodAsync()
{
// . . . .
}
Use the await keyword in the code calling an asynchronous process/method.
int resultValue = await ExampleMethodAsync();
Note: await can only be used in an async method modified by the async keyword.
Use one of the correct return types in the async method in order to get results
return types for an async method need to be one of the following:
Task if your method has a return statement in which the operand has type TResult.
Task if your method has no return statement or has a return statement with no operand.
void if you're writing an async event handler.
Adding the “Async” suffix at the end of the calling method name. This is not required but is considered
a convention for writing async methods in C#.
public async Task<int> ExampleCallingMethodAsync()
{
// . . . .
}
Include at least one await expression in the async method code.
The suspension of an async method at an await expression doesn't
constitute an exit from the method, and finally blocks don’t run.
public async Task<int> ExampleMethodAsync()
{
//some code
string pageContents = await client.GetStringAsync(uri);
//some more code
return pageContents.Length;
}
Note:
You have to adjust what your async method is returning. The object being returned has to match the type Task<T> of your async method
If an async method doesn’t use an await operator to mark a suspension point, the method
executes as a synchronous method does, despite the async modifier. The compiler issues a
warning for such methods.
Below is a typical method converted to an asynchronous method
Example
private void WebPage(string someURI)
{
WebClient webClient = new WebClient();
string pageContent = webClient.DownloadString(someURI);
Console.WriteLine(pageContent);
}
changed to:
private async void WebPageAsync(string someURI)
{
WebClient webClient = new WebClient();
string pageContent = await webClient.DownloadStringTaskAsync(someURI);
Console.WriteLine(pageContent);
}
I hope this was helpful?

Async and await: Why doesn't an async method whose signature defines a return type of Task explicitly return a Task?

I used How to: Extend the async Walkthrough by Using Task.WhenAll (C#) to develop a program to independently submit multiple database queries asynchronously. The program works ok, but there is a nuance I don't understand and for which I can't find an explanation:
In the example, the signature for the method SumPageSizesAsync is:
private async Task SumPageSizesAsync()
The body of the method SumPageSizesAsync does not explicitly return the whenAllTask object (i.e., the WhenAll roll-up Task). Why doesn't the method SumPageSizesAsync explicitly return the whenAllTask task? How does the line of code in StartButton_Click that calls SumPageSizesAsync "know" which task is being returned?
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
.
Task sumTask = SumPageSizesAsync();
.
}
private async Task SumPageSizesAsync()
{
HttpClient client = new HttpClient() { MaxResponseContentBufferSize = 1000000 };
List<string> urlList = SetUpURLList();
IEnumerable<Task<int>> downloadTasksQuery = from url in urlList select ProcessURLAsync(url);
Task<int>[] downloadTasks = downloadTasksQuery.ToArray();
Task<int[]> whenAllTask = Task.WhenAll(downloadTasks);
int[] lengths = await whenAllTask;
int total = lengths.Sum();
// Display the total count for all of the web addresses.
resultsTextBox.Text += string.Format("\r\n\r\nTotal bytes returned: {0}\r\n", total);
// where's the return statement?
}
Why doesn't the method SumPageSizesAsync explicitly return the whenAllTask task?
That is not the Task that this method returns. The Task that is returned is one that is created by the compiler.
As soon as the await is encountered, the following happens:
- If whenAllTask is already finished, then just continue executing the rest of the method.
- Otherwise, create a Task that does the following things:
1: Wait for whenAllTask to finish.
2: and then execute the rest of the method.
This Task is then immediately returned.
I always think of the return statement as being embedded in the await. "return a Task that waits for this other Task to finish and then executes the rest of this method."
I completely agree on answer posted by #Dennis_E and more information can also be found in C# 6 in a Nutshell (page number 600).
According to author, while executing the async function, with task return type. If there is no explicit return of task from the method body, complier creates a task.
This task is then used for following purpose,
Singling completion of the method.
Asynchronous call chaining.
It is an async void function, meaning it returns Task. Since it is already awaited inside, there is nothing no return here.

Task, Action in same dictionary or alternative architecture?

I hope I can get this explained right on the first try:
I have a Dictionary<int, Action> MyActions. I have a method that looks like this:
int actionNumber = 0;
while (isRunning) {
if (Phases.TryGetValue(actionNumber, out var action))
{
action.Invoke();
}
actionNumber++;
}
The idea is that the methods are run after each other whenever the one before has finished. And when there is an error I have the actionNumber saved so I can return to the correct last Method and continue from there.
The Methods I put into the Dictionary were initially only simple void Methods. Now I found myself I also have to put async Methods in there cause some of them have await in their body. This means the dictionary would have to keep void Methods and async Task Methods inside them. And the while loop must have an await or else it will just continue when it runs a async Task Method.
My Solutions:
Solution A:
Make the dictionary a Dictionary<int, Task> MyActions and make everything a Task even if it is a simple void Method. Change the while loop to:
int actionNumber = 0;
while (isRunning) {
if (Phases.TryGetValue(actionNumber, out var task))
{
Task.Run(() => task).Wait();
}
actionNumber++;
}
Solution B:
Keep everything as it is. Wrap the async Task Methods into another void Method which itself awaits the Task Method. Put this void Method inside the action dictionary.
Solution C:
Turn every async Task Method into void Method and rewrite await to .Result.
Any other better solutions? I tend to go with Solution A because it is easier for other developers to look at the Dictionary and clearly see it all has to be Tasks.
How about Dictionary<int, Func<Task>>?
You can add all async methods there and await them while they are executed. If you want to add a non-async method returning void simply wrap it with:
Func<Task> wrapper = () => {
simpleSyncMethod();
return Task.CompletedTask;
}

Why is it not necessary to return a Task when the signature is public async Task MethodName?

I have some code that is working fine but I don't understand why. My method performs some SQL operations using the ExecuteReaderAsync, ExecuteNonQueryAsync, and WriteToServerAsync. WriterToServerAsync is the last one I call.
I originally wrote the method with the signature public async void Run() but the Hangfire job runner I am using won't accept async unless it returns a Task. I changed the signature to async Task Run() and then tried to figure out how to return a Task from the method.
I thought that I could just return the same task that was being returned from WriteToServerAsync but this would not compile. I ended deleting the return statement altogether. The compiler does not complain and the method works fine.
public async Task Run()
{
// Start querying the source first as it is the slowest operation...
var sqlSourceConnection = new SqlConnection(sourceConnectionString);
// The query is kind of slow so it needs more than the default 30 second timeout...
var sqlSourceCommand = new SqlCommand(SourceDataSql, sqlSourceConnection) { CommandTimeout = 180 };
sqlSourceConnection.Open();
// Query the records from the source...
var querySourceDataTask = sqlSourceCommand.ExecuteReaderAsync();
// Delete existing records from target to make way for the new set...
var sqlTargetConnection = new SqlConnection(targetConnectionString);
sqlTargetConnection.Open();
var sqlTargetTransaction = sqlTargetConnection.BeginTransaction(IsolationLevel.ReadCommitted);
var deleteRowsTask = sqlDeleteCommand.ExecuteNonQueryAsync();
// Wait for the delete and query tasks to finish before attempting the bulk copy...
await Task.WhenAll(deleteRowsTask, querySourceDataTask);
await sqlBulkCopy.WriteToServerAsync(querySourceDataTask.Result);
}
Why does this compile and work without a return statement for the Task?
Why does this compile and work without a return statement for the Task?
Because the return type Task is the equivalent of void (a method that doesn't return any value) for an asynchronous method that can be awaited.
Please refer to the following links for more information about the async/await keywords in C#.
Async/Await - Best Practices in Asynchronous Programming: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Asynchronous Programming with async and await (C#): https://msdn.microsoft.com/en-us/library/mt674882.aspx

async and await not returning to caller as expected

I have a simple async and await example I'm trying to work through and the execution is not returning to the caller as I expect. Here is the top level method:
protected async void MyDDL_SelectedIndexChanged(object sender, EventArgs e)
{
Task longRunningTask = LongRunningOperationAsync();
DoOtherStuff1();
DoOtherStuff2();
DoOtherStuff3();
await longRunningTask;
}
Here is the LongRunningOperationAsync method which does not work as expected and runs synchronously:
private async Task LongRunningOperationAsync()
{
var myValues = await GetStuffViaLongRunningTask();
//Code to work with myValues here...
}
Here is the definition of GetStuffViaLongRunningTask
private async Task<IList<MyClass>> GetStuffViaLongRunningTask()
{
//...Calls to get and build up IList<MyClass>
return results;
}
The problem is the above code does not return to the caller and begin running the DoOtherStuff1(); method as I would expect. However, instead of calling my own method and replacing it with a call to await Task.Delay(10000); like all the simple examples show, the code works as expected:
private async Task LongRunningOperationAsync()
{
//Returns to caller as expected:
await Task.Delay(10000);
}
The caller using the code above has longRunningTask with a WaitingForActivation as its status instead of RanToCompletion, showing it is still processing.
You might say my GetStuffViaLongRunningTask() method runs so quickly and I just can't see the results. However it always takes between 3-7 seconds to run and you can tell when debugging that the call is blocking and synchronous.
What am I doing incorrectly here, so that my call to LongRunningOperationAsync() is not working asynchronously when reaching the await word to call LongRunningOperationAsync within that method?
Assuming that //...Calls to get and build up IList<MyClass> is synchronous CPU bound work, the issue there is that GetStuffViaLongRunningTask won't return until it either ends, or hits its first await call. You should be getting a compiler warning on that method as it's an async method that doesn't have an await in it.
Instead, the method simply shouldn't be async, to clearly indicate to it's callers that it's synchronous work. Just adjust the signature to:
private IList<MyClass> GetStuffViaLongRunningTask()
Then when calling it use Task.Run to ensure that the long running CPU bound work is done in another thread:
private async Task LongRunningOperationAsync()
{
var myValues = await Task.Run(() => GetStuffViaLongRunningTask());
//Code to work with myValues here...
}
//...Calls to get and build up IList<MyClass>
You need to show us which calls are being made. If you want to use async/await with this structure then you need to make an async call.
If your GetStuffViaLongRunningTask function is not doing async calls then you can start a new task like the following:
private Task<IList<MyClass>> GetStuffViaLongRunningTask()
{
return Task.Factory.StartNew(() =>
{
//...Calls to get and build up IList<MyClass>
// You can make synchronous calls here
return list;
});
}

Categories

Resources