When converting to async, you want to start at the "leaves" and work towards your controllers/UI. I've done a lot of conversions, and that's the best approach I've found.
So, first identify any operations that are naturally asynchronous; anything I/O-bound is a good bet. You've already identified one: the database calls.
Next, start at the lowest-level code, and make that asynchronous. This is where your problem is coming in; you're thinking about forcing asynchrony in the middle by using Task.Run, but you need to dive deeper to a lower level and make it asynchronous all the way.
For example, I'll assume that your repository is using Entity Framework and that your All<T> method looks something like this:
public List<T> All<T>()
{
return _context.Set<T>().ToList();
}
Then you would start with making an asynchronous version of this repository method:
public Task<List<T>> AllAsync<T>()
{
return _context.Set<T>().ToListAsync();
}
Once you have at least one asynchronous repository method in place, you can start to change your service layer to be asynchronous, so this code:
public string GetProjects()
{
var json = JsonConvert.SerializeObject(_repository.All<Projects>());
return json;
}
becomes this:
public async Task<string> GetProjectsAsync()
{
var json = JsonConvert.SerializeObject(await _repository.AllAsync<Projects>());
return json;
}
Once the service layer is asynchronous, then you can change your controllers to be asynchronous.
Task<string>is correct behavior. Just put async before yourGetProjectsAsync()method.