I have .NET core Web API which as service layer. Service layer has all EF code.
If have basecontroller with this code
protected Task<IActionResult> NewTask(Func<IActionResult> callback)
{
return Task.Factory.StartNew(() =>
{
try
{
return callback();
}
catch (Exception ex)
{
Logger.LogError(ex.ToString());
throw;
}
});
}
In controller action I wrap all calls to service in above method e.g. :
[HttpGet("something")]
public async Task<IActionResult> GetSomething(int somethingId)
{
return await NewTask(() =>
{
var result = _somethingService.GetSomething(somethingId);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
});
}
Is this correct pattern considering tomorrow I may have more than one service calls in action or making calls to other webservice. Please advise.
In general, you should make a method asynchronous if the synchronous method blocks the ASP.NET request thread while doing no work. By making the call asynchronous, the ASP.NET request thread is not blocked doing no work while it waits for the web service request to complete.
Asynchronous Programming and its Advantage It is a programming technique that allows us to execute our flows without blocking our application or causing the thread pool starvation. The often misconception is that by using the async and await keywords we gain better performance in terms of the speed of our application.
Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.
ASP.NET Core apps should be designed to process many requests simultaneously. Asynchronous APIs allow a small pool of threads to handle thousands of concurrent requests by not waiting on blocking calls. Rather than waiting on a long-running synchronous task to complete, the thread can work on another request.
i want my api to benefit from async await thing.does above pattern will serve these needs
No, it does not. Running synchronous work on the thread pool gives you the drawbacks of synchronous and asynchronous code, with the benefits of neither.
something service has some crud operations which use entityframework core
Currently, your action method is what I call "fake asynchronous" - it looks asynchronous (e.g., using await
), but in fact is just running blocking code on a background thread. On ASP.NET, you want true asynchrony, whicn means you must be async all the way. For more about why this is bad on ASP.NET, see the first half of my intro to async
on ASP.NET article (it mostly deals with ASP.NET non-core, but the first part talking about synchronous vs asynchronous requests is valid for any kind of server).
To make this truly asynchronous, you should start at the lowest level - in this case, your EFCore calls. They all support asynchrony. So, replace API calls like x.FirstOrDefault()
with await x.FirstOrDefaultAsync()
(and the same for all your creates/updates/deletes, etc).
Then allow async
/await
to grow naturally from there; the compiler will guide you. You'll end up with asynchronous methods on your somethingService
which can be consumed as such:
[HttpGet("something")]
public async Task<IActionResult> GetSomething(int somethingId)
{
var result = await _somethingService.GetSomethingAsync(somethingId);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
}
Okay, first of all, you should stop using Task.Factory.StartNew
and use Task.Run
only when you have heavy CPU-bound work that you want to run on a thread pool thread. In you case you don't really need that at all. Also you should remember that you should only use Task.Run
when calling a method and not in the implementation of the method. You can read more about that here.
What you really want in your case is to have asynchronous work inside your service (I'm not really sure you even need a service in your case) when you are actually making a call to the database and you want to use async/await and not just run some stuff on a background thread.
Basically your service should look something like this (if you are sure you need a service):
class PeopleService
{
public async Task<Person> GetPersonByIdAsync(int id)
{
Person randomPerson = await DataContext.People.FirstOrDefaultAsync(x => x.Id == id);
return randomPerson;
}
}
As you can see your service now makes async calls to the database and that's basically what your pattern should be. You can apply this to all your operations(add/delete/ etc..)
After making your service asynchronous you should be easily able to consume the data in the action.
Your actions should look something like this:
[HttpGet("something")]
public async Task<IActionResult> GetPerson(int id)
{
var result = await PeopleService.GetPersonByIdAsync(id);
if (result != null)
return Ok(result);
else
return NotFound("Role not found");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With