I switched the OnGet
of my razor page to be async and I noticed some of my controls would no longer load reliably.
I have a kendo multiselect on the page and once I switched to async it only loads the list of options about 50% of the time. Controls that don't contain a list of options seem to load ok. I switched back to synchronous and everything loads reliably again. Is async/await not appropriate for use when fetching data from the DB to populate the page?
Here's the async version of my OnGet
:
public async void OnGet(int securityGroupId)
{
if (securityGroupId == -1)
{
SecurityGroup = new SecurityGroup();
SecurityGroup.IsActive = true;
}
else
{
SecurityGroup = await DL.GetEntityByIdAsync<SecurityGroup, int>(securityGroupId);
}
RoleList = await DL.GetLookupListAsync<Role>();
RoleList = RoleList.OrderBy(r => r.Text).ToList();
}
Here's the synchronous version:
public void OnGet(int securityGroupId)
{
if (securityGroupId == -1)
{
SecurityGroup = new SecurityGroup();
SecurityGroup.IsActive = true;
}
else
{
SecurityGroup = DL.GetEntityById<SecurityGroup, int>(securityGroupId);
}
RoleList = DL.GetLookupList<Role>().OrderBy(r => r.Text).ToList();
}
RoleList
is: public List<DDL> RoleList { get; set; }
DDL
is a class containing a string Id and a string Text;
Here's the async version of GetEntityById
:
public async Task<TEntity> GetEntityByIdAsync<TEntity, TId>(TId id) where TEntity : class, IIdentifiable<TId>, new()
where TId : IEquatable<TId>
{
var entity = new TEntity();
try
{
entity = await db.Set<TEntity>().FirstOrDefaultAsync(t => t.Id.Equals(id));
}
catch (Exception ex)
{
throw ex;
}
return entity;
}
Here's the synchronous version:
public TEntity GetEntityById<TEntity, TId>(TId id) where TEntity : class, IIdentifiable<TId>, new()
where TId : IEquatable<TId>
{
var entity = new TEntity();
try
{
entity = db.Set<TEntity>().FirstOrDefault(t => t.Id.Equals(id));
}
catch (Exception ex)
{
throw ex;
}
return entity;
}
Here's the async version of GetLookupList
:
public async Task<List<DDL>> GetLookupListAsync<TEntity>() where TEntity : class, IDDLable
{
List<DDL> ddl = new List<DDL>();
try
{
ddl = await db.Set<TEntity>().Select(lu => new DDL { Id = lu.DDLId, Text = lu.DDLText }).ToListAsync();
}
catch (Exception ex)
{
throw ex;
}
return ddl;
}
Here's the synchronous version:
public List<DDL> GetLookupList<T>() where T : class, IDDLable
{
List<DDL> ddl = new List<DDL>();
try
{
ddl = db.Set<T>().Select(lu => new DDL { Id = lu.DDLId, Text = lu.DDLText }).ToList();
}
catch (Exception ex)
{
throw ex;
}
return ddl;
}
The multiselect is defined as:
@(Html.Kendo().MultiSelectFor(m => m.SelectedRoles)
.DataValueField("Id")
.DataTextField("Text")
.AutoClose(false)
.Placeholder("Select Role(s)...")
.BindTo(Model.RoleList))
Changing the return type of OnGet from void
to Task
resolved the issue. The Async
suffix didn't have any effect, I believe it's just a matter of naming convention.
The function now reads:
public async Task OnGetAsync(int securityGroupId)
{
if (securityGroupId == -1)
{
SecurityGroup = new SecurityGroup();
SecurityGroup.IsActive = true;
}
else
{
SecurityGroup = await DL.GetEntityByIdAsync<SecurityGroup, int>(securityGroupId);
SelectedRoles = SecurityGroup.RoleIdList;
}
RoleList = await DL.GetLookupListAsync<Role>();
RoleList = RoleList.OrderBy(r => r.Text).ToList();
}