should I use await on return? - asp.net-mvc

I have an MVC web application, the controller action calls a code in a business layer, which in turn calls an API:
public async Task<ActionResult> TestAction(){
Info something = await businessLayer.GetInfoAsync();
return View(something);
}
in the business layer I have GetInfoAsync defined as follows:
public async Task<Info> GetInfoAsync(){
return await myLib.GetAsync<Info>();
}
in my library I have GetAsync defined as follows:
public async Task<T> GetAsync(){
//do something
var data = await aService.Get<T>();
return data;
}
As you can see above GetInfoAsync method just makes a call to myLib.GetAsync and returns whatever value myLib.GetAsync returns.
Could I just get rid of async/await for GetInfoAsync, and define it as follows :
public Task<Info> GetInfoAsync(){
return myLib.GetAsync<Info>();
}
Thanks !

Yes, you can (and should) get rid of async/await in the middle layer.
If your async method is just awaiting a single task (and that's all it does), then the async just adds overhead.

Related

Is it possible to make GlobalConfiguration.Configure asynchronous?

The entry point to a web api project is in the global.asax and the boilerplate code is this:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
This calls the Register method which is static void. During setup, I want to make various calls that use async Task. Is there an elegant way to do this other than wrapping every async call in Task.Run(() => myMethod).Wait();?
If I am understanding your question, I think you could do something like this:
Task<string> getStringTask = someGetStringAsyncMethod();
Task<object> getObjectTask = someGetObjectAsyncMethod();
Task.WaitAll(new Task[] {
getStringTask,
getObjectTask,
});
string theString = getStringTask.Result();
object theObject = getObjectTask.Result();
I guess if you don't need the results then you could call the async methods directly in the WaitAll.

MVC5 - Deadlock with async Tasks?

I think my web application is suffering from deadlock when I'm calling YouTube API services, so I want to know how to resolve this in the correct manner. I suspect it's a similar scenario to the following: Why does this async action hang?
Please can somebody advise, in very simple terms, why my web application hangs (see inline comments) and how it should be correctly resolved? Thanks!
public ActionResult Index()
{
YouTubeHelper yth = new YouTubeHelper();
bool unpublishVideo = yth.UpdateVideoOnYouTube(17, "public").Result;
}
public async Task<bool> UpdateVideoOnYouTube(int propertyId, string publishStatus)
{
.....
YouTubeService youtubeService = await GetYouTubeService(db);
.....
}
public async Task<YouTubeService> GetYouTubeService(ApplicationDbContext db)
{
....
if (!await credential.RefreshTokenAsync(CancellationToken.None)) //It hangs here!!
{
....
}
....
}
The deadlock is explained here. In summary, your asynchronous methods are needing the ASP.NET request context before they can complete, but the call to Result is blocking the ASP.NET request context until the asynchronous methods are already completed.
To avoid the deadlock, don't block on async code. Use await instead of Result:
public async Task<ActionResult> Index()
{
YouTubeHelper yth = new YouTubeHelper();
bool unpublishVideo = await yth.UpdateVideoOnYouTube(17, "public");
}

Mark page as "async = true" for a Visual Studio MVC Project

I am using Edge.js so that I can call Node.js from C#. According to the documentation in the link I would do that similar to the following:
[HttpPost]
public ActionResult Input(InputModel obj)
{
validateInput(obj);
return View();
}
private async void validateInput(object obj)
{
var func = Edge.Func(#"
return function (data, callback){
var username = data.username,
email = data.email;
callback(null, username);
}
");
ViewBag.Msg = (string)await func(obj);
}
However, I get the following run time error:
Additional information: An asynchronous operation cannot be started at this time.
Asynchronous operations may only be started within an asynchronous handler or module or during
certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the
Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an
"async void" method, which is generally unsupported within ASP.NET request processing. Instead,
the asynchronous method should return a Task, and the caller should await it.
My question is two-fold:
1.How do I make the page, async=true. I know how to do this for a web forms project but not a MVC project.
2.Is there a better way to do what I am trying to do? A red flag will probably go up when you see that I am returning void however this is do to the fact that Edge.js is being used. Even so, I have tried returning a Task and then task.Wait() in the calling method but the task never finishes.
After trying some different things, the following solution worked for me.
Even though I answered my own question, and it seems trivial, I am not removing this question as there are not a lot of knowledge on the web about Edge.js.
[HttpPost]
public async Task<ActionResult> Input(InputModel obj)
{
ViewBag.Msg = await validateInput(obj);
return View();
}
private async Task<string> validateInput(object obj)
{
var func = Edge.Func(#"
return function (data, callback){
var username = data.username,
email = data.email;
callback(null, username);
}
");
return (string)await func(obj);
}

Not able to return ActionResult from a controller which calls async method

I am working on a sample app to query an api and I am trying to move the generic piece into QueryAsync which queries and returns Task. This function will be called from a controller action GetData which can returns Task too. Here, I am awaiting while retrieving the result from QueryAsync. I feel it is not required as QueryAsync is not returning an awaitable object. But then if I don't, i will not be able to return ActionResult from GetData controller. Is my thinking and implementation here correct? Sorry, but I am new to using Async with MVC.
private async Task<ActionResult> QueryAsync<T>(string url)
{
Task<string> response_task = HttpClientService.HttpClientService.GetRequest(url);
IEnumerable<T> model = JsonConvert.DeserializeObject<IEnumerable<T>>(await response_task);
return View(model);
}
//
// GET:
public async Task<ActionResult> GetData()
{
string _address = "https://someurl";
return await QueryAsync<ClassType>(_address);
}
You are returning an awaitable Task from QueryAsync, which is a Task that "asynchronously" runs GetRequest, then synchronously deserializes the result and returns an ActionResult. Think of those operations as a whole, squeezed into an awaitable Task.
From async/await API perspective, your implementation is correct. Your implementation is equivalent to the following (ignoring generic method):
public async Task<ActionResult> GetData()
{
var url = "https://someurl";
var response = await HttpClientService.HttpClientService.GetRequest(url);
var model = JsonConvert.DeserializeObject<IEnumerable<ClassType>>(response);
return View(model);
}

How to wait until all tasks are finished before running code

I am trying to write a multi threading search and then display all the results once the tasks have finished running but currently I don't understand how to process the results once all the tasks are complete
My code is as follows:
private async void DoSearchAsync()
{
var productResults = await SearchProductsAsync(CoreCache.AllProducts);
var brochureResults = await SearchBrochuresAsync(CoreCache.AllBrochures);
_searchResults.AddRange(productResults);
_searchResults.AddRange(brochureResults);
ResultsCount = _searchResults.Count;
}
Where _searchResults is a List<SearchResult>
My understanding is that it will do both of the awaits simultaneously and then add the products to the search results. However when I call this in my controller:
public ActionResult Index(string searchText)
{
SearchHelper helper = new SearchHelper(searchText);
helper.DoSearchAsync();
return View(helper);
}
It is displaying the page before the searches are complete so no results are showing up. How do I make it wait for the results to finish before showing the page?
I've had a look into Tasks.Wait but don't know how to apply it to the above as it expects an array of tasks
private Task<List<SearchResult>> SearchProductsAsync(IEnumerable<Product> products)
{
return Task<List<SearchResult>>.Factory.StartNew(() => GetProducts(products));
}
private Task<List<SearchResult>> SearchBrochuresAsync(IEnumerable<Assets> brochures)
{
return Task<List<SearchResult>>.Factory.StartNew(() => GetBrochures(brochures));
}
Every time you call Factory.StartNew or Task.Run inside an ASP.NET controller, you grab a thread from ThreadPool. That thread could be otherwise serving another incoming HTTP request. So, your're really hurting your web app scalability. This may be a serious issue, depending on how many concurrent HTTP requests your web app is expected to receive.
Are you OK with that? If so, the code could look like this:
private async Task DoSearchAsync()
{
var productResults = SearchProductsAsync(CoreCache.AllProducts);
var brochureResults = SearchBrochuresAsync(CoreCache.AllBrochures);
await Task.WhenAll(productResults, brochureResults);
_searchResults.AddRange(productResults.Result);
_searchResults.AddRange(brochureResultsbrochure.Results);
ResultsCount = _searchResults.Count;
}
public async Task<ActionResult> Index(string searchText)
{
SearchHelper helper = new SearchHelper(searchText);
await helper.DoSearchAsync();
return View(helper);
}
Note I changed async void to async Task for DoSearchAsync, and made your controller method async, so it returns Task<ActionResult>.
My understanding is that it will do both of the awaits simultaneously
This is not correct Pete. The await means that it will pause execution of the current method until such time that the Async method being called completes. So your 2 searches will not run in Parallel.
For clarification, see the first line of the MSDN documentation....
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes.
You should use Task.WhenAll to wait for both searches to complete. As WhenAll supports returning Task<T> and both of your Async searches return a List<SearchResult> you can combine the results of both searches and await them both in one statement...
var searchProducts = Task.Factory.StartNew(() => GetProducts(CoreCache.AllProducts));
var searchBrochure = Task.Factory.StartNew(() => GetBrochures(CoreCache.AllBrochures));
var allResults = await Task.WhenAll(new [] { searchProducts, searchBrochure });
//allResults is List<SearchResult>[]
For completeness, its worth noting that allResults will contain 2 result sets. It does not perform a union on the 2 sets.
A complete working example for LinqPad can be found here on GitHub
You can use a task factory, then call wait on the resulting task:
Task taskA = Task.Factory.StartNew(() => DoSomeWork(10000000));
taskA.Wait();
Console.WriteLine("taskA has completed.");
http://msdn.microsoft.com/en-us/library/dd537610(v=vs.110).aspx
You can make it wait for the results to finish before displaying the page by making your function NOT be async.
Or if you want async you could move the search functions to be called by an AJAX call triggered when your page is loaded
You need to wait for the function to complete. In order to do that, first make it return a task:
private async Task DoSearchAsync()
then await it:
public async Task<ActionResult> Index(string searchText)
{
SearchHelper helper = new SearchHelper(searchText);
await helper.DoSearchAsync();
return View(helper);
}
For more information, see http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

Resources