MVC - Asynchronous method acts different from synchronous method

MVC - Asynchronous method acts different from synchronous method

QternocqQternocq Posts: 5Questions: 3Answers: 0

I had this method:

public ActionResult AjaxHourLinesDataGridHandler(DataTablesParam param, DateTime? dateParam, int client)
        {
            if (client == 0) return null;
            var clientObject = db.GetCurrentClients(User).FirstOrDefault(c => c.ClientId.Equals(client));
            if (clientObject == null) return null;

            var hourlines = db.GetHourLinesUpTillDateByClient(clientObject, dateParam.Value).OrderBy(h => h.Project.Description).ThenBy(h => h.From);
            
            var count = hourlines.Count();

            var result = hourlines.ToList()
                .Select(hourline => new[] { 
                    hourline.Code
                    hourline.From.ToString("dd-MM-yyyy"),
                    hourline.User.FirstName + " " + hourline.User.LastName,
                    string.Format(CultureInfo.InvariantCulture, "{0:N2}", hourline.Hours),
                    hourline.ProjectCode,
                    hourline.Description
                }).ToList();
            
            return Json(new
            {
                sEcho = param.sEcho,
                iTotalRecords = count,
                iTotalDisplayRecords = param.iDisplayLength,
                aaData = result
            },
            JsonRequestBehavior.AllowGet);
        }

It worked just fine.
I changed it to something asynchronous:

public async Task<ActionResult> AjaxHourLinesDataGridHandler(DataTablesParam param, DateTime? dateParam, int client)
        {
            if (client == 0) return null;
            var clientObject = await db.GetCurrentClients(User).FirstOrDefaultAsync(c => c.ClientId.Equals(client));
            if (clientObject == null) return null;

            var hourlines = db.GetHourLinesUpTillDateByClient(clientObject, dateParam.Value).OrderBy(h => h.Project.Description).ThenBy(h => h.From);
            
            var count = hourlines.Count();

            var listResult = await hourlines.ToListAsync();
            var result = listResult
                .Select(hourline => new[] { 
                    "<input type=\"button\" id=\"devaluate"+hourline.HourLineId+"\" name=\"devaluate"+hourline.HourLineId+"\" value=\"afw\" class=\"btn-xs " + (hourline.HourlineStatus != null && !hourline.HourlineStatus.Description.Equals("Open") ? "btn-danger" : "btn-info") + "\" /><input type=\"checkbox\" name=\"charge\" id=\"charge"+hourline.HourLineId+"\" " + (hourline.HourlineStatus != null && hourline.HourlineStatus.Description.Equals("Open") ? "checked=\"checked\"" : string.Empty) + " style=\"margin-left: 5px;\" " + (hourline.HourlineStatus != null && !hourline.HourlineStatus.Description.Equals("Open") ? "disabled=\"disabled\"" : string.Empty) + " />",
                    hourline.From.ToString("dd-MM-yyyy"),
                    hourline.User.FirstName + " " + hourline.User.LastName,
                    string.Format(CultureInfo.InvariantCulture, "{0:N2}", hourline.Hours),
                    hourline.ProjectCode,
                    hourline.Description
                }).ToList();
            
            return Json(new
            {
                sEcho = param.sEcho,
                iTotalRecords = count,
                iTotalDisplayRecords = param.iDisplayLength,
                aaData = result
            },
            JsonRequestBehavior.AllowGet);
        }

And as soon as I step over the third line of code (the first await), it jumps back to Internet Explorer (or Firefox) and shows me an Ajax error (which ends with /tn/7). I've debugged it as far as seeing the GetCurrentClients() method return what I need, so the problem is when Its running the FirstOrDefaultAsync. I've seen other async methods work fine. For example:

public async Task<ActionResult> AjaxProjectDataGridHandler(DataTablesParam param, int client, DateTime dateParam)
        {
            var clientObject = db.GetCurrentClients(User).Single(c => c.ClientId.Equals(client));
            var yearAndProjects = db.GetHourLinesUpTillDateByClient(clientObject, dateParam).OrderBy(h => h.Project.Code).ThenBy(h => h.ProjectYear.HasValue ? h.ProjectYear : 0).GroupBy(h => new { h.ProjectYear, h.Project.Code, h.Project.Description, h.Project.ProjectId });
            var count = yearAndProjects.Count();

            var listResult = await yearAndProjects.ToListAsync();
            var result = listResult.Select(
                                item => new[] { 
                                    "test"
                                });

            return Json(new
            {
                sEcho = param.sEcho,
                iTotalRecords = count,
                iTotalDisplayRecords = param.iDisplayLength,
                aaData = result
            },
            JsonRequestBehavior.AllowGet);
        }

As I looked at the difference, I noticed this is only using ToListAsync, which is also in the other method. I tried removing the asynchronous part from the FirstOrDefault (3rd line in the erroring method) and the code works. Do you know why? I know it's only a minor performance thing and won't be noticeable, but I'm trying to be consistent. Other than that, I want to know why one works and the other doesn't and whether it's something in .Net, Ajax, the browser or Datatables.

Answers

This discussion has been closed.