Why doesn't async execution work in `select`? - c#

I am calling this action (ASP.Net Core 2.0) over AJAX:
[HttpGet]
public async Task<IActionResult> GetPostsOfUser(Guid userId, Guid? categoryId)
{
var posts = await postService.GetPostsOfUserAsync(userId, categoryId);
var postVMs = await Task.WhenAll(
posts.Select(async p => new PostViewModel
{
PostId = p.Id,
PostContent = p.Content,
PostTitle = p.Title,
WriterAvatarUri = fileService.GetFileUri(p.Writer.Profile.AvatarId, Url),
WriterFullName = p.Writer.Profile.FullName,
WriterId = p.WriterId,
Liked = await postService.IsPostLikedByUserAsync(p.Id, UserId),// TODO this takes too long!!!!
}));
return Json(postVMs);
}
But it took too long to response (20 seconds!!!) in case I have many post objects in posts
array (e.g. 30 posts).
That is caused because of this line await postService.IsPostLikedByUserAsync.
Digging into the source code of this function:
public async Task<bool> IsPostLikedByUserAsync(Guid postId, Guid userId)
{
logger.LogDebug("Place 0 passed!");
var user = await dbContext.Users
.SingleOrDefaultAsync(u => u.Id == userId);
logger.LogDebug("Place 1 passed!");
var post = await dbContext.Posts
.SingleOrDefaultAsync(u => u.Id == postId);
logger.LogDebug("Place 2 passed!");
if (user == null || post == null)
return false;
return post.PostLikes.SingleOrDefault(pl => pl.UserId == userId) != null;
}
The investigations showed, after some seconds, ALL "Place 1 passed!" logging methods are executed together for every post object. In other words, it seems that every post awaits until the previous post finishes executing this part:
var user = await dbContext.Users
.Include(u => u.PostLikes)
.SingleOrDefaultAsync(u => u.Id == userId);
And then -when every post finishes that part- the place 1 of log is executed for all post objects.
The same happens for logging place 2, every single post seems to await for the previous post to finish executing var post = await dbContext.Pos..., and then the function can go further to execute log place 2 (after few seconds from log 1, ALL log 2 appear together).
That means I have no asynchronous execution here. Could some one help me to understand and solve this problem?
UPDATE:
Changing the code a bit to look like this:
/// <summary>
/// Returns all post of a user in a specific category.
/// If the category is null, then all of that user posts will be returned from all categories
/// </summary>
/// <param name="userId"></param>
/// <param name="categoryId"></param>
/// <returns></returns>
[Authorize]
[HttpGet]
public async Task<IActionResult> GetPostsOfUser(Guid userId, Guid? categoryId)
{
var posts = await postService.GetPostsOfUserAsync(userId, categoryId);
var i = 0;
var j = 0;
var postVMs = await Task.WhenAll(
posts.Select(async p =>
{
logger.LogDebug("DEBUG NUMBER HERE BEFORE RETURN: {0}", i++);
var isLiked = await postService.IsPostLikedByUserAsync(p.Id, UserId);// TODO this takes too long!!!!
logger.LogDebug("DEBUG NUMBER HERE AFTER RETURN: {0}", j++);
return new PostViewModel
{
PostId = p.Id,
PostContent = p.Content,
PostTitle = p.Title,
WriterAvatarUri = fileService.GetFileUri(p.Writer.Profile.AvatarId, Url),
WriterFullName = p.Writer.Profile.FullName,
WriterId = p.WriterId,
Liked = isLiked,
};
}));
return Json(postVMs);
}
That shows, that this line "DEBUG NUMBER HERE AFTER RETURN" is printed for ALL select methods together, that means that ALL select methods waits for each other before going further, how can I prevent that?
UPDATE 2
Substituting the previous IsPostLikedByUserAsyncmethod, with the following one:
public async Task<bool> IsPostLikedByUserAsync(Guid postId, Guid userId)
{
await Task.Delay(1000);
}
Showed no problem in async running, I had to wait only 1 second, not 1 x 30.
That means it is something specific to EF.
Why does the problem happen ONLY with entity framework (with the original function)? I notice the problem even with only 3 post objects! Any new ideas?

The deductions you've made are not necessarily true.
If these methods were firing in a non-asynchronous fashion, you would see all of the logs from one method invocation reach the console before the next method invocation's console logs. You would see the pattern 123123123 instead of 111222333. What you are seeing is that the three awaits seem to synchronize after some asynchronous batching occurs. Thus it appears that the operations are made in stages. But why?
There are a couple reasons this might happen. Firstly, the scheduler may be scheduling all of your tasks to the same thread, causing each task to be queued and then processed when the previous execution flow is complete. Since Task.WhenAll is awaited outside of the Select loop, all synchronous portions of your async methods are executed before any one Task is awaited, therefore causing all of the "first" log invocations to be called immediately following the invocation of that method.
So then what's the deal with the others syncing up later? The same thing is happening. Once all of your methods hit their first await, the execution flow is yielded to whatever code invoked that method. In this case, that is your Select statement. Behind the scenes, however, all of those async operations are processing. This creates a race condition.
Shouldn't there be some chance of the third log of some methods being called before the second log of another method, due to varying request/response times? Most of the time, yes. Except you've introduced a sort of "delay" in to the equation, making the race condition more predictable. Console logging is actually quite slow, and is also synchronous. This causes all of your methods to block at the logging line until the previous logs have completed. But blocking, by itself, may not be enough to make all of those log calls sync up in pretty little batches. There may be another factor at play.
It would appear that you are querying a database. Since this is an IO operation, it takes considerably longer to complete than other operations (including console logging, probably). This means that, although the queries aren't synchronous, they will in all likelihood receive a response after all of the queries/requests have already been sent, and therefore after the second log line from each method has already executed. The remaining log lines are processed eventually, and therefore fall in to the last batch.
Your code is being processed asynchronously. It just doesn't look quite how you might expect. Async doesn't mean random order. It just means some code flow is paused until a later condition is met, allowing other code to be processed in the mean time. If the conditions happen to sync up, then so does your code flow.

Actually async execution works, but it doesn't work as you expect. Select statement starts tasks for all posts and then they all work concurrently that leads you to performance problems you.
The best approach to achieve expected behavior is to reduce the degree of parallelism. There are no build-in tools to do that so I can offer 2 workarounds:
Use TPL DataFlow library. It is developed by Microsoft but not very popular. You can easily find enough examples though.
Manage parallel tasks by yourself with SemaphoreSlim. It would look like this:
semaphore = new SemaphoreSlim(degreeOfParallelism);
cts = new CancellationTokenSource();
var postVMs = await Task.WhenAll(
posts.Select(async p =>
{
await semaphore.WaitAsync(cts.Token).ConfigureAwait(false);
cts.Token.ThrowIfCancellationRequested();
new PostViewModel
{
PostId = p.Id,
PostContent = p.Content,
PostTitle = p.Title,
WriterAvatarUri = fileService.GetFileUri(p.Writer.Profile.AvatarId, Url),
WriterFullName = p.Writer.Profile.FullName,
WriterId = p.WriterId,
Liked = await postService.IsPostLikedByUserAsync(p.Id, UserId),// TODO this takes too long!!!!
}
semaphore.Release();
}));
And don't forget to use .ConfigureAwait(false) whenever it's possible.

Related

C# Add to a List Asynchronously in API

I have an API which needs to be run in a loop for Mass processing.
Current single API is:
public async Task<ActionResult<CombinedAddressResponse>> GetCombinedAddress(AddressRequestDto request)
We are not allowed to touch/modify the original single API. However can be run in bulk, using foreach statement. What is the best way to run this asychronously without locks?
Current Solution below is just providing a list, would this be it?
public async Task<ActionResult<List<CombinedAddressResponse>>> GetCombinedAddress(List<AddressRequestDto> requests)
{
var combinedAddressResponses = new List<CombinedAddressResponse>();
foreach(AddressRequestDto request in requests)
{
var newCombinedAddress = (await GetCombinedAddress(request)).Value;
combinedAddressResponses.Add(newCombinedAddress);
}
return combinedAddressResponses;
}
Update:
In debugger, it has to go to combinedAddressResponse.Result.Value
combinedAddressResponse.Value = null
and Also strangely, writing combinedAddressResponse.Result.Value gives error below "Action Result does not contain a definition for for 'Value' and no accessible extension method
I'm writing this code off the top of my head without an IDE or sleep, so please comment if I'm missing something or there's a better way.
But effectively I think you want to run all your requests at once (not sequentially) doing something like this:
public async Task<ActionResult<List<CombinedAddressResponse>>> GetCombinedAddress(List<AddressRequestDto> requests)
{
var combinedAddressResponses = new List<CombinedAddressResponse>(requests.Count);
var tasks = new List<Task<ActionResult<CombinedAddressResponse>>(requests.Count);
foreach (var request in requests)
{
tasks.Add(Task.Run(async () => await GetCombinedAddress(request));
}
//This waits for all the tasks to complete
await tasks.WhenAll(tasks.ToArray());
combinedAddressResponses.AddRange(tasks.Select(x => x.Result.Value));
return combinedAddressResponses;
}
looking for a way to speed things up and run in parallel thanks
What you need is "asynchronous concurrency". I use the term "concurrency" to mean "doing more than one thing at a time", and "parallel" to mean "doing more than one thing at a time using threads". Since you're on ASP.NET, you don't want to use additional threads; you'd want to use a form of concurrency that works asynchronously (which uses fewer threads). So, Parallel and Task.Run should not be parts of your solution.
The way to do asynchronous concurrency is to build a collection of tasks, and then use await Task.WhenAll. E.g.:
public async Task<ActionResult<IReadOnlyList<CombinedAddressResponse>>> GetCombinedAddress(List<AddressRequestDto> requests)
{
// Build the collection of tasks by doing an asynchronous operation for each request.
var tasks = requests.Select(async request =>
{
var combinedAddressResponse = await GetCombinedAdress(request);
return combinedAddressResponse.Value;
}).ToList();
// Wait for all the tasks to complete and get the results.
var results = await Task.WhenAll(tasks);
return results;
}

How does parallelization work on async/await?

I have the following code, that I intend to run asynchronously. My goal is that GetPictureForEmployeeAsync() is called in parallel as many times as needed. I'd like to make sure that 'await' on CreatePicture does not prevent me from doing so.
public Task<Picture[]> GetPictures(IDictionary<string, string> tags)
{
var query = documentRepository.GetRepositoryQuery();
var employees = query.Where(doc => doc.Gender == tags["gender"]);
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
}
private Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
var base64PictureTask = blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var documentTask = documentRepository.GetItemAsync(employee.ID.ToString());
return CreatePicture(tags, base64PictureTask, documentTask);
}
private static async Task<Picture> CreatePicture(IDictionary<string, string> tags, Task<string> base64PictureTask, Task<Employee> documentTask)
{
var document = await documentTask;
return new Picture
{
EmployeeID = document.ID,
Data = await base64PictureTask,
ID = document.ID.ToString(),
Tags = tags,
};
}
If I understand it correctly, Task.WhenAll() is not affected by the two awaited tasks inside CreatePicture() because GetPictureForEmployeeAsync() is not awaited. Am I right about this? If not, how should I restructure the code to achieve what I want?
I'd like to make sure that 'await' on CreatePicture does not prevent me from doing so.
It doesn't.
If I understand it correctly, Task.WhenAll() is not affected by the two awaited tasks inside CreatePicture() because GetPictureForEmployeeAsync() is not awaited. Am I right about this?
Yes and no. The WhenAll isn't limited in any way by the awaited tasks in CreatePicture, but that has nothing to do with whether GetPictureForEmployeeAsync is awaited or not. These two lines of code are equivalent in terms of behavior:
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
return Task.WhenAll(employees.Select(async employee => await GetPictureForEmployeeAsync(employee, tags)));
I recommend reading my async intro to get a good understanding of how async and await work with tasks.
Also, since GetPictures has non-trivial logic (GetRepositoryQuery and evaluating tags["gender"]), I recommend using async and await for GetPictures, as such:
public async Task<Picture[]> GetPictures(IDictionary<string, string> tags)
{
var query = documentRepository.GetRepositoryQuery();
var employees = query.Where(doc => doc.Gender == tags["gender"]);
var tasks = employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)).ToList();
return await Task.WhenAll(tasks);
}
As a final note, you may find your code cleaner if you don't pass around "tasks meant to be awaited" - instead, await them first and pass their result values:
async Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
var base64PictureTask = blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var documentTask = documentRepository.GetItemAsync(employee.ID.ToString());
await Task.WhenAll(base64PictureTask, documentTask);
return CreatePicture(tags, await base64PictureTask, await documentTask);
}
static Picture CreatePicture(IDictionary<string, string> tags, string base64Picture, Employee document)
{
return new Picture
{
EmployeeID = document.ID,
Data = base64Picture,
ID = document.ID.ToString(),
Tags = tags,
};
}
The thing to keep in mind about calling an async method is that, as soon as an await statement is reached inside that method, control immediately goes back to the code that invoked the async method -- no matter where the await statement happens to be in the method. With a 'normal' method, control doesn't go back to the code that invokes that method until the end of that method is reached.
So in your case, you can do the following:
private async Task<Picture> GetPictureForEmployeeAsync(Employee employee, IDictionary<string, string> tags)
{
// As soon as we get here, control immediately goes back to the GetPictures
// method -- no need to store the task in a variable and await it within
// CreatePicture as you were doing
var picture = await blobRepository.GetBase64PictureAsync(employee.ID.ToString());
var document = await documentRepository.GetItemAsync(employee.ID.ToString());
return CreatePicture(tags, picture, document);
}
Because the first line of code in GetPictureForEmployeeAsync has an await, control will immediately go right back to this line...
return Task.WhenAll(employees.Select(employee => GetPictureForEmployeeAsync(employee, tags)));
...as soon as it is invoked. This will have the effect of all of the employee items getting processed in parallel (well, sort of -- the number of threads that will be allotted to your application will be limited).
As an additional word of advice, if this application is hitting a database or web service to get the pictures or documents, this code will likely cause you issues with running out of available connections. If this is the case, consider using System.Threading.Tasks.Parallel and setting the maximum degree of parallelism, or use SemaphoreSlim to control the number of connections used simultaneously.

Threading in c# while making put calls

I am new to threading world of c#. I read there are different ways to do threading like sequential.
My scenario is below. Which one would be more suitable for the below.
I have list of complex objects. I will be making calls to PUT endpoint for each object [body of put] separately. There can be 1000 or more objects in the list. And I cannot pass all the objects at one and hence I have to pass each object in every call to the put endpoint. In this way, I have to make 1000 calls separately if there are 1000 objects.
Each put call is independent of each other while I have to store the properties of the response back from each call.
I was thinking to apply threading concept to above but not sure which one and how to do it.
Any suggestions would be greatly appreciated.
Thanking in advance.
As per the comments below,
Putting the method signatures here and adding more details.
I have IEnumerable<CamelList>. For each camel, I have to make a put request call and update the table from the response of each call. I will write a new method that will accept this list and make use of below 2 methods to make call and update table. I have to ensure, I am making not more than 100 calls at the same time and the API I am calling can be called by the same user 100 times per minute.
We have a method as
public Camel SendRequest(handler, uri, route, Camel); //basically takes all the parameters and provide you the Camel.
We have a method as public void updateInTable(Entity Camel); //updates the table.
HTTP calls are typically made using the HttpClient class, whose HTTP methods are already asynchronous. You don't need to create your own threads or tasks.
All asynchronous methods return a Task or Task<T> value. You need to use theawaitkeyword to await for the operation to complete asynchronously - that means the thread is released until the operation completes. When that happens, execution resumes after theawait`.
You can see how to write a PUT request here. The example uses the PutAsJsonAsync method to reduce the boilerplate code needed to serialize a Product class into a string and create a StringContent class with the correct content type, eg:
var response = await client.PutAsJsonAsync($"api/products/{product.Id}", product);
response.EnsureSuccessStatusCode();
If you want to PUT 1000 products, all you need is an array or list with the products. You can use LINQ to make multiple calls and await the tasks they return at the end :
var callTasks = myProducts.Select(product=>client.PutAsJsonAsync($"api/products/{product.Id}", product);
var responses = await Task.WhenAll(callTasks);
This means that you have to wait for all requests to finish before you can check if any one succeeded. You can change the body of Select to await the response itself :
var callTasks = myProducts.Select(async product=>{
var response=await client.PutAsJsonAsync($"api/products/{product.Id}", product);
if (!response.IsSuccessStatusCode)
{
//Log the error
}
return response.StatusCode;
});
var responses=await Task.WhenAll(callTasks);
It's better to conver the lambda into a separate method though, eg PutProductAsync :
async Task<HttpStatusCode> PutProduct(Product product,HttpClient client)
{
var response=await client.PutAsJsonAsync($"api/products/{product.Id}", product);
if (!response.IsSuccessStatusCode)
{
//Log the error
}
return response.StatusCode;
};
var callTasks = myProducts.Select(product=>PutProductAsync(product));
var responses=await Task.WhenAll(callTasks);
I'm going to suggest using Microsoft's Reactive Framework for this. You need to NuGet "System.Reactive" to get the bits.
Then you can do this:
var urls = new string[1000]; //somehow populated;
Func<string, HttpContent, IObservable<string>> putCall = (u, c) =>
Observable
.Using(
() => new HttpClient(),
hc =>
from resp in Observable.FromAsync(() => hc.PutAsync(u, c))
from body in Observable.FromAsync(() => resp.Content.ReadAsStringAsync())
select body);
var callsPerTimeSpanAllowed = 100;
var timeSpanAllowed = TimeSpan.FromMinutes(1.0);
IObservable<IList<string>> bufferedIntervaledUrls =
Observable.Zip(
Observable.Interval(timeSpanAllowed),
urls.ToObservable().Buffer(callsPerTimeSpanAllowed),
(_, buffered_urls) => buffered_urls);
var query =
from bufferedUrls in bufferedIntervaledUrls
from url in bufferedUrls
from result in putCall(url, new StringContent("YOURCONTENTHERE"))
select new { url, result };
IDisposable subscription =
query
.Subscribe(
x => { /* do something with each `x.url` & `x.result` */ },
() => { /* do something when it is all finished */ });
This code is breaking the URLs into blocks (or buffers) of 100 and putting them on a timeline (or interval) of 1 minute apart. It then calls the putCall for each URL and returns the result.
It's probably a little advanced for you now, but I thought this answer might be useful just to see how clean this can be.

Async calls never returns in Asp.Net MVC

I am return a list which basically calls the two async operations:
[HttpPost]
public ActionResult List(DataSourceRequest command, ProductListModel model)
{
var categories = _productService.GetAllProducts(model.SearchProductName,
command.Page - 1, command.PageSize);
var gridModel = new DataSourceResult
{
Data = categories.Select(async x =>
{
var productModel = x.ToModel();
var manufacturer = await _manufacturerService.GetManufacturerById(x.ManufacturerId);
var category = await _categoryService.GetCategoryById(x.CategoryId);
productModel.Category = category.Name;
productModel.Manufacturer = manufacturer.Name;
return productModel;
}),
Total = categories.TotalCount
};
return Json(gridModel);
}
It is an ajax request (from client side) but on front-end it never returns. Is there any a deadlock ?
Building up my answer from several comments and #usr's answer:
Data in the code above is actually IEnumerable<Task<ProductModel>>, not IEnumerable<ProductModel>. This is because the lambda passed to Select is async.
Most likely, the JSON serializer is going over this structure and enumerating the properties on the Task<ProductModel> instances, including Result.
I explain on my blog why accessing Result will cause a deadlock in this case. In a nutshell, it's because the async lambda will attempt to resume execution on the ASP.NET request context after its await. However, the ASP.NET request context is blocked on the call to Result, locking a thread inside that request context until the Task<T> completes. Since the async lambda cannot resume, it cannot complete that task. So both things are waiting for each other, and you get a classic deadlock.
There are some suggestions to use await Task.WhenAll, which I would normally agree with. However, in this case you're using Entity Framework and got this error:
A second operation started on this context before a previous asynchronous operation completed.
This is because EF cannot perform multiple asynchronous calls concurrently within the same db context. There are a couple ways around this; one is to use multiple db contexts (essentially multiple connections) to do the calls concurrently. IMO a simpler way is to make the asynchronous calls sequentially instead of concurrently:
[HttpPost]
public async Task<ActionResult> List(DataSourceRequest command, ProductListModel model)
{
var categories = _productService.GetAllProducts(model.SearchProductName,
command.Page - 1, command.PageSize);
var data = new List<ProductModel>();
foreach (var x in categories)
{
var productModel = x.ToModel();
var manufacturer = await _manufacturerService.GetManufacturerById(x.ManufacturerId);
var category = await _categoryService.GetCategoryById(x.CategoryId);
productModel.Category = category.Name;
productModel.Manufacturer = manufacturer.Name;
data.Add(productModel);
}
var gridModel = new DataSourceResult
{
Data = data,
Total = categories.TotalCount
};
return Json(gridModel);
}
The way to debug is is to pause the debugger during the hang. There you will find that some serializer is blocking on Task.Result or similar.
You fill the Data property with a IEnumerable<Task>. The serializer probably calls Result at some point and that's the classic ASP.NET deadlock. You probably should wrap the Select call with await Task.WhenAll(x.Select(...)).
And even then it might be unsafe to concurrently run those lambdas.

Multiple parallel awaitable tasks

I'm experimenting with ways to improve performance in our ASP.NET applications. One of the things I'm looking at is using parallelism and making operations async to try to reduce processing time and improve throughput. I started by mocking up something we do fairly frequently, issue multiple database retrievals to render a page.
public ActionResult Index()
{
var dal = new Dal();
var cases = new List<Case>();
cases.AddRange( dal.GetAssignedCases() );
cases.AddRange( dal.GetNewCases() );
return View( "Cases", cases );
}
The two Dal methods use Thread.Sleep(2000) to simulate a query and just return a collection of hard-coded objects. I run this with Apache Bench using ab -c 1 -n 1 and it takes about four seconds. My first attempt to try to improve it was:
public ActionResult Index()
{
var dal = new Dal();
var assignedCases = Task.Factory.StartNew( () => dal.GetAssignedCases() );
var newCases = Task.Factory.StartNew( () => dal.GetNewCases() );
IEnumerable<Case>[] allCases = Task.WhenAll( assignedCases, newCases ).Result;
return View( "Cases", allCases.SelectMany( c => c ) );
}
When I run this using the same ab command it shows about two seconds, which makes sense because I'm running two tasks each of which takes two seconds but they're running in parallel.
When I change the benchmark to 10 concurrent requests (i.e. ab -n 10 -c 10) I get the following.
Fulfilled Original Parallel
50% 4014 2038
66% 4015 2039
75% 4017 4011
The rest of the numbers up to 100% are similar in both columns.
I'm assuming that what I'm running into here is thread pool contention. About 2/3 of the requests are fulfilled quickly and after that stuff is sitting around waiting for threads to service the requests. So I think maybe if I added async to the mix I could get even more requests being served more quickly. That's where I start having problems and I don't know if the problem is the way I'm simulating long-running queries or the way I'm using the language feature or if I'm just completely on the wrong track and the light at the end of the tunnel is an on-coming train. :-)
First thing I did was create a DalAsync. In DalAsync I replaced the Thread.Sleep(2000) with await Task.Delay(2000), marked each method with the async keyword and changed the return type from IEnumerable<Case> to Task<IEnumerable<Case>>. I then wrote a new controller method pieced together from information I've read in a half-dozen blog posts and MSDN articles.
public async Task<ActionResult> Index()
{
var dal = new DalAsync();
var assignedCases = dal.GetAssignedCasesAsync();
var newCases = dal.GetNewCasesAsync();
var allCases = await Task.WhenAll( assignedCases, newCases );
return View( "Cases", allCases.SelectMany( c => c ) );
}
When I run this using ab it never finishes, even with one request it ends up timing out. I also tried the following variation, which works but returns numbers almost identical to the original version (which sort of makes sense, because it seems I'm serializing the queries again).
var assignedCases = await dal.GetAssignedCasesAsync();
var newCases = await dal.GetNewCasesAsync();
var allCases = new List<Case>( assignedCases );
allCases.AddRange( newCases );
What I'd like to have happen is:
Run the two queries in parallel
When the controller is waiting for the Dal methods to respond it frees up the thread and lets other
requests execute.
Your first code sample should work, however to my eyes it appears a bit strange. Task.WhenAll was introduced to be a non-blocking operation, i.e. you would use await Task.WhenAll(myTasks). By using the .Result, you are turning it into a blocking operation, however it does not feel entirely natural to be used this way.
I think what you are really after is Task.WaitAll(params Task[]) which is designed to be a blocking operation.
Your second code sample however, looks near perfect and exactly what I would go for. Implementing asynchronous code throughout the code-base always makes for a much cleaner implementation.
Though I was unable to reproduce you case and mine runs OK but to me it seems like you are running into a deadlock. Try forcing your async tasks to return their result to a different sync context like this:
public async Task<ActionResult> Index()
{
var dal = new DalAsync();
var assignedCases = Task.Run(async () => await dal.GetAssignedCasesAsync());
var newCases = Task.Run(async () => await dal.GetNewCasesAsync());
var allCases = await Task.WhenAll( assignedCases, newCases).ConfigureAwait(false);
return View( "Cases", allCases.SelectMany( c => c ) );
}

Categories