i'm going through a tutorial in the asp.net vnext series. I came across something in the tutorial that doesn't make a lot of sense:
using System.Linq;
using Microsoft.AspNet.Mvc;
using TodoList.Models;
using System.Threading.Tasks;
namespace TodoList.ViewComponents
{
public class PriorityListViewComponent : ViewComponent
{
private readonly ApplicationDbContext db;
public PriorityListViewComponent(ApplicationDbContext context)
{
db = context;
}
// Synchronous Invoke removed.
public async Task<IViewComponentResult> InvokeAsync(int maxPriority, bool isDone)
{
string MyView = "Default";
// If asking for all completed tasks, render with the "PVC" view.
if (maxPriority > 3 && isDone == true)
{
MyView = "PVC";
}
var items = await GetItemsAsync(maxPriority, isDone);
return View(MyView, items);
}
private Task<IQueryable<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
{
return Task.FromResult(GetItems(maxPriority, isDone));
}
private IQueryable<TodoItem> GetItems(int maxPriority, bool isDone)
{
var items = db.TodoItems.Where(x => x.IsDone == isDone &&
x.Priority <= maxPriority);
string msg = "Priority <= " + maxPriority.ToString() +
" && isDone == " + isDone.ToString();
ViewBag.PriorityMessage = msg;
return items;
}
}
}
They are creating a wrapper for a sync method and just calling Task.FromResults()
so its async. First of all its still going to block so whats the point? Probably behind the scenes its just creating a TaskCompletionSource
& wrapping the results in Task
object. They then await
the results which probably just is creating extra overhead that is not needed i would think. The db call they are making through EF is still sync. Am i missing something here or is a bad example?
It's a bad example. It serves no value to create an async wrapper around a synchronous operation and such a decision should usually be left to the library consumer.
I believe the only asynchronous methods that should be exposed are those that have scalability benefits over their synchronous counterparts. Asynchronous methods should not be exposed purely for the purpose of offloading: such benefits can easily be achieved by the consumer of synchronous methods
From Should I expose asynchronous wrappers for synchronous methods?
And while there are times when it's appropriate (like complying with a Task
returning interface or abstract method) this doesn't seem to be the case.
You're quite right that it's just going to end up blocking, and that making everything have an asynchronous API but with synchronous behavior is only going to perform [slightly] worse.
As for why you'd do it; you'd do it so that it exposes an identical API to the actually asynchronous versions, allowing both implementations to meet an interface or other type of contract allowing them to be used by a caller that doesn't know which implementation is actually being used. It is likely being used here as a stop gap while the application is transitioning to being entirely asynchronous, but to which certain pieces do not yet have asynchronous implementations. When you upgrade your database provider and have actually asynchronous versions of these methods it'll mean you only need to change this implementation, and won't need to change anything on the caller's side of things.
Of course, it has its fair share of potential problems if you end up with a caller expecting a method like this to actually behave asynchronously and not block for a long period of time, given that it doesn't do that at all.
This is a hack; not one without purpose, but you do need to recognize it as such.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With