Asynchrony on ASP MVC - c#

I would want to increase the performance of my web application for future scalability issues,
One scenario that i think of is that, if i need a list that needs to be filtered from the database.
Here is the rough draft that i made:
public IEnumerable<test> getL(IEnumerable<test> filter)
{
//do some filtering from the list then return it
return filter;
}
public async Task<ActionResult> Index()
{
context con = new context();
//do more stuff of stuff
IEnumerable<test> get = await Task.Run(() => { return getL(con.dep.ToList()); });
return View(get);
}
I am kinda new with C#'s asynchrony so i am kinda wondering if i am doing this correct. Did i start the asynchronous call properly?

On ASP.NET, you should avoid Task.Run. This is because Task.Run will free up the current thread by using another thread. So you incur the penalty of an additional context switch for no reason. This code will decrease scalability and performance, not increase it.
Instead, use await for I/O-based tasks. For example, getting the data from the database:
public async Task<ActionResult> Index()
{
context con = new context();
var list = await con.dep.ToListAsync();
IEnumerable<test> get = getL(list);
return View(get);
}

Related

Too many nested async methods. Is that a problem?

The following code gets a list of investments belonging to a customer from 3 different resources. The flow starts with a controller's call and follows the flow described below where all methods are declared as async and called with await operator.
I'm wondering if is there a problem making all methods as async. Is there any performance penalty? Is it a code smell or an anti-pattern?
I know there are things that must be waited like access url, get data from cahce, etc. But I think there are things like filling a list or sum some few values doesn't need to be async.
Below follow the code (some parts where ommited for clearness):
Controller
{HttpGet]
public async Task<IActionResult> Get()
{
Client client = await _mediator.Send(new RecuperarInvestimentosQuery());
return Ok(cliente);
}
QueryHandler
public async Task<Client> Handle(RecoverInvestimentsQuery request, CancellationToken cancellationToken)
{
Client client;
List<Investiment> list = await _investimentBuilder.GetInvestiments();
client = new Cliente(request.Id, list);
return client;
}
InvestmentBuilder
public async Task<List<Investiment>> GetInvestiments()
{
ListInvestiments builder = new ListInvestiments();
await builder.BuildLists(_builder);
// here I get the List<Investiment> list already fulfilled to return to the controller
return list;
}
BuildLists
public async Task BuildLists(IBuilder builder)
{
Task[] tasks = new Task[] {
builder.GetFundsAsync(), //****
builder.ObterTesouro(),
builder.ObterRendaFixa()
};
await Task.WhenAll(tasks);
}
Funds, Bonds and Fixed Income Services (***all 3 methods are equal, only its name vary, so I just put one of them for the sake of saving space)
public async Task GetFundsAsync()
{
var listOfFunds = await _FundsService.RecoverFundsAsync();
// listOfFunds will get all items from all types of investments
}
Recover Funds, Bonds and Fixed Incomes methods are equals too, again I just put one of them
public async Task<List<Funds>> RecoverFundsAsync()
{
var returnCache = await _clientCache.GetValueAsync("fundsService");
// if not in cache, so go get from url
if (returnCache == null)
{
string url = _configuration.GetValue<string>("Urls:Funds");
var response = await _clienteHttp.ObterDadosAsync(url);
if (response != null)
{
string funds = JObject.Parse(response).SelectToken("funds").ToString();
await _clienteCache.SetValueAsync("fundService", funds);
return JsonConvert.DeserializeObject<List<Funds>>(fundos);
}
else
return null;
}
return JsonConvert.DeserializeObject<List<Funds>>(returnCache);
}
HTTP Client
public async Task<string> GetDataAsync(string Url)
{
using (HttpClient client = _clientFactory.CreateClient())
{
var response = await client.GetAsync(Url);
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStringAsync();
else
return null;
}
}
Cache Client
public async Task<string> GetValueAsync(string key)
{
IDatabase cache = Connection.GetDatabase();
RedisValue value = await cache.StringGetAsync(key);
if (value.HasValue)
return value.ToString();
else
return null;
}
Could someone give a thought about that?
Thanks in advance.
Your code looks okay for me. You are using async and await just for I/O and web access operations, and it perfectly fits for async and await purposes:
For I/O-bound code, you await an operation that returns a Task or Task inside of an async method.
For CPU-bound code, you await an operation that is started on a background thread with the Task.Run method.
Once you've used async and await, then all pieces of your code tends to become asynchronous too. This fact is described greatly in the MSDN article - Async/Await - Best Practices in Asynchronous Programming:
Asynchronous code reminds me of the story of a fellow who mentioned
that the world was suspended in space and was immediately challenged
by an elderly lady claiming that the world rested on the back of a
giant turtle. When the man enquired what the turtle was standing on,
the lady replied, “You’re very clever, young man, but it’s turtles all
the way down!” As you convert synchronous code to asynchronous code,
you’ll find that it works best if asynchronous code calls and is
called by other asynchronous code—all the way down (or “up,” if you
prefer). Others have also noticed the spreading behavior of
asynchronous programming and have called it “contagious” or compared
it to a zombie virus. Whether turtles or zombies, it’s definitely true
that asynchronous code tends to drive surrounding code to also be
asynchronous. This behavior is inherent in all types of asynchronous
programming, not just the new async/await keywords.

C# Tasks Calling same instance

I'm fairly new to tasks and want to implement them on my application. What I want is to do an ajax request on my client side when the page loads, to a function that calls all the catalogs that I need and returns a JSON of all the objects to my client. This function on the server side is the one I created to have multiple tasks. So I have the following questions regarding this:
Is it a good practice to load all catalogs needed for that page and return a JSON object?
Does it actually work as multi thread if the tasks call the same instance of a class? Or is it better to create the instance inside each task?
public JsonResult GetCatalogs()
{
JsonResult jSonResult = new JsonResult();
try
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
Task<IList<CustomObject1>> task1 = Task.Factory.StartNew(() =>
{
IList<CustomObject1> resultList1 = catalogsRepository.getFirstCatalog();
return resultList1;
});
Task<IList<CustomObject2>> task2 = Task.Factory.StartNew(() =>
{
IList<CustomObject2> resultList2 = catalogsRepository.getSecondCatalog();
return resultList2;
});
Task<IList<CustomObject3>> task3 = Task.Factory.StartNew(() =>
{
IList<CustomObject3> resultList3 = catalogsRepository.getThirdCatalog();
return resultList3;
});
jSonResult = Json(new
{
result1 = task1.Result,
learningMaterialTypeList = task2.Result,
contentAssociatedList = task13.Result
});
jSonResult.MaxJsonLength = int.MaxValue;
jSonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
catch (Exception ex)
{
log.Error(ex);
return Json(new Error { messageCode = 1, message = ex.Message });
}
return jSonResult;
}
Or is it better to create the instance inside each task?
public JsonResult GetCatalogs()
{
JsonResult jSonResult = new JsonResult();
try
{
Task<IList<CustomObject1>> task1 = Task.Factory.StartNew(() =>
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
IList<CustomObject1> resultList1 = catalogsRepository.getFirstCatalog();
return resultList1;
});
Task<IList<CustomObject2>> task2 = Task.Factory.StartNew(() =>
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
IList<CustomObject2> resultList2 = catalogsRepository.getSecondCatalog();
return resultList2;
});
Task<IList<CustomObject3>> task3 = Task.Factory.StartNew(() =>
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
IList<CustomObject3> resultList3 = catalogsRepository.getThirdCatalog();
return resultList3;
});
jSonResult = Json(new
{
result1 = task1.Result,
learningMaterialTypeList = task2.Result,
contentAssociatedList = task13.Result
});
jSonResult.MaxJsonLength = int.MaxValue;
jSonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
}
catch (Exception ex)
{
log.Error(ex);
return Json(new Error { messageCode = 1, message = ex.Message });
}
return jSonResult;
}
I'm using MVC .NET 4.0 with jQuery, Thank you in advance.
Your action method should be async:
public async Task<JsonResult> GetCatalogs()
Once your method is async, everything else is much easier. You can do away with those Task.Run() calls and just call the methods normally (as long as they as async) and await them. It may make sense to make those lambdas into separate, async methods (or even C#7 local methods):
protected async Task<IList<CustomObject1>> GetResults1()
{
CatalogsRepository catalogsRepository = new CatalogsRepository();
var resultList1 = catalogsRepository.getFirstCatalog();
return await resultList1.ToListAsync();
});
Important: To get results you should use await. Never use Result in an async ASP.NET environment because it will deadlock.
var jsonResult = Json(new
{
result1 = await task1,
learningMaterialTypeList = await task2,
contentAssociatedList = await task3
});
As for your questions:
Is it a good practice to load all catalogs needed for that page and return a JSON object?
There is no rule against it. It's a design decision for you to make. The pro is fewer round trips, the con is coupling all those things together in a public interface makes the architecture a bit more brittle.
Does it actually work as multi thread if the tasks call the same instance of a class? Or is it better to create the instance inside each task?
In true multithreading, it is better in general to work on separate instances so that each thread can have its own independent memory cache. That being said, async is not the same as multithreading, and in fact in ASP.NET you're guaranteed that no two of your tasks will be executing simultaneously (unless you do something special to make that happen). Instead you get one thread at a time. The thread might change, and your async code will jump around await points, but only one piece of code gets to run at once, by design.
1.I think that by returning a JSON object you mean an action which returns a JsonObject and is called by ajax from the client side. You can do this in most places of your app but keep in mind that you can lose a lot of benefits from pure MVC. The second thing is jQuery and Ajax are a bit hard to maintain and in case of complex views you will have to write a lot of code, very often hard to test.
A very common concept in asp.net MVC is returning ViewModels/Models via GET methods and then sending data from forms with the use of asp.net helpers back to the controllers. If you use data annotation attributes and jQuery unobtrusive library you can build really nice validation, very easy to maintain on the backend and on the client side. The client-side validation will be generated just for FREE based on the .net attributes which shorten your time in development. With Ajax calls, you can do similar but the code will be more clunky.
2 and 3.Your controller should contain as less business logic as possible and all the logic should be moved to other layers, services etc. Your actual code is over too complicated.
Try to use interfaces and IOC. Avoid creating instances of objects like you do now in the controller. It’s hard to write tests for such a class.
I think something like this would be better:
private readonly ICatalogService _catalogService;
// Dependency injection thanks to Inversion of Control
public BlahController(ICatalogService catalogService){
_catalogService=catalogService;
}
public async JsonResult GetCatalogs(params..){
return await catalogService.getCatalogs(params..); //or catalogRepository
}
So you can move all the business logic out of the controller to some separate class.

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.

Parallel Task Code to make multiple db accesses

I am trying to speed up some code of mine,
I make 2 or 3 reads to a slow database, and I want to make these calls run in paralle.
FSKWebInterfaceEntities dbSrc = new FSKWebInterfaceEntities();
public void main()
{
var TaskUsr = GetUserAsync(dev);
var TaskOldCompany = GetOldCompanyAsync(dev);
await Task.WhenAll();
var usr = TaskUsr.Result;
var oldCompanyName = TaskOldCompany.Result;
.....
use my two variables to insert a new entry into my localdb
}
private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}
private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}
On my two helper methods its is underlined green and said that there is no await, and therefore will run synchronously. However I cant return return await dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
How should I modify my code to make the two reads in parallel?
You can await that line because it is not an async method. You can't really await database calls as they are not thread safe. See this thread for an example of a way to do it, and a better explanation as to why not. You can consider using SqlCommands that have async methods as well.
You cannot use the same EF DbContext concurrently. From the EF Team's statement about thread safety:
For the moment, EF will detect if the developer attempts to execute
two async operations at one time and throw.
You still can call them asynchronously, but sequentially:
public async Task main()
{
var sr = await GetUserAsync(dev);
var oldCompany = await GetOldCompanyAsync(dev);
.....
use my two variables to insert a new entry into my localdb
}
Updated to address the comment:
Could you possible post a simple example of how I would change my
above code to use the multiple dbcontext, As I don't really know the
correct way to do it, I would be coding in the dark.
Something like below. I'm not an expert in EF to assure you this will actually improve the processing time. There may be significant overhead of opening the database connection for each context.
public async Task main()
{
var TaskUsr = GetUserAsync(dev);
var TaskOldCompany = GetOldCompanyAsync(dev);
await Task.WhenAll(TaskUsr, TaskOldCompany);
var usr = TaskUsr.Result;
var oldCompanyName = TaskOldCompany.Result;
.....
use my two variables to insert a new entry into my localdb
}
private async Task<ut_User> GetUserAsync(ut_UserAPNdevices dev)
{
using (var dbSrc = new FSKWebInterfaceEntities())
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID);
}
private async Task<String> GetOldCompanyAsync(ut_UserAPNdevices dev)
{
using (var dbSrc = new FSKWebInterfaceEntities())
return dbSrc.ut_User.FirstOrDefault(x => x.UserID == dev.UserID).Company;
}

Are there any benefits of using a task if we synchronously wait for the result?

I have a Partial Action that needs to call an async method that returns Task from a DB Call. Since I can't have an async Partial Action I need to wait for the task to complete:
public ActionResult TopMenu()
{
var topMenuTask = Task.Run<IEnumerable<TopMenuItem>>( () =>
{ return _menuService.GetTopMenu(); });
topMenuTask.Wait();
//view model population code goes here
return PartialView(viewModel);
}
It is my understanding the benefit of doing an async DB (IO) call is we are requeueing the thread to the thread pool so it can serve more requests while the IO is finishing, but wouldn't this be a moo point in this case as we are synchronously waiting for it?
I assume from your problem description that GetTopMenu returns a Task, and thus should actually be called GetTopMenuAsync.
In this case, your best option is probably what you are already doing:
public ActionResult TopMenu()
{
var topMenuTask = Task.Run(() => _menuService.GetTopMenuAsync());
var topMenu = topMenuTask.Result;
//view model population code goes here
return PartialView(viewModel);
}
It is my understanding the benefit of doing an async DB (IO) call is we are requeueing the thread to the thread pool so it can serve more requests while the IO is finishing, but wouldn't this be a moo point in this case as we are synchronously waiting for it?
Correct. By wrapping the (asynchronous) DB access within a (synchronous) partial action, the code is nullifying the benefits of async.
This is a limitation of the platform (ASP.NET MVC). Please vote on the issue and on uservoice.
You will summon a thread from the thread pool that will execute that logic but the web request thread will be blocked waiting for the result. So no, there is no benefit.
Why can´t you do this?:
public async Task<ActionResult> TopMenu()
{
var topMenu = await Task.Run<IEnumerable<TopMenuItem>>( () => { return _menuService.GetTopMenu(); });
//view model population code goes here
return PartialView(viewModel);
}
Another option is to use the classic async MVC way, but you have to derive your controller from AsyncController rather than Controller:
public void TopMenuAsync()
{
AsyncManager.OutstandingOperations.Increment();
Task.Run<IEnumerable<TopMenuItem>>(() => { return _menuService.GetTopMenu(); })
.ContinueWith(t =>
{
AsyncManager.Parameters["topMenu"] = t.Result;
AsyncManager.OutstandingOperations.Decrement();
});
}
public ActionResult TopMenuCompleted(TopMenuItem topMenu)
{
//view model population code goes here
return PartialView(viewModel);
}
You should not be using Task.Run in ASP.NET in the fist place. You're still limited by a single HTTP request/response time frame, it won't speed up the content delivery and will just introduce an extra thread switch, check this.
So, your action should look like this:
public ActionResult TopMenu()
{
var topMenu = return _menuService.GetTopMenu();
//view model population code goes here
return PartialView(viewModel);
}
If your partial views may take a while to render, consider using a technique like this:
http://blog.michaelckennedy.net/2012/11/13/improve-perceived-performance-of-asp-net-mvc-websites-with-async-partialviews/
You are correct.. and it is generally the reason why you defer the decision of using a Task up to the caller, or provide async and non-async versions of the call (e.g: GetTopMenu and GetTopMenuAsync). If you force the use of an async call then you run into situations just like this.
Your alternative is to load the view and asynchronously make the call via AJAX. You can also give the user visual feedback in this scenario. Utilising await in this scenario will free up the worker process for IIS to continue serving requests.

Categories