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.
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");
}
Related
I want to build asynchronous Web API using .NET Core
If I have async Task that's awaiting for a result from the service as below
[HttpGet("User/")]
public async Task<IActionResult> GetUser()
{
var result = await _service.GetUser();
return Ok(result);
}
Now in _service.GetUser we do more than one task such as querying the database more than once.
So my question is do we have to use async & await as well in _service.GetUser, or is it enough that the caller method do? I'm kind of confused.
public async Task<UserResponseDTO> GetUser(UserRequestDTO userRequestDTO)
{
var userId = await _utilities.getUserId(); //shall we use it?
var user = await _dbContext.getFullUserInfo //shall we use it?
.Where(P => P.userId == userId).FirstOrDefault();
if (!string.IsNullOrEmpty(userRequestDTO.email))
{
var emailExists = await _dbContext.getFullUserInfo.Where(p =>
p.Email == userRequestDTO.email).AnyAsync(); //shall we use it?
}
await _dbContext.SaveChangesAsync();
return _mapper.Map<UserResponseDTO>(user);
}
I want to build asynchronous Web API Using .NET Core
Why?
There are a number of incorrect answers to that question; the most common one is probably "to make it faster". "To make it more scalable" I would say is only semi-correct.
The correct answer is "I have asynchronous work do to", where "asynchronous" in this context is roughly the same as "I/O-bound".
In your example code, you want an asynchronous Web API call because that call queries/updates the database.
So my question is do we have to use async & await as well in _service.GetUser or is it enough that the caller method do?
Once you have the correct reasoning around "why", the solution is clearer. Specifically, you want to have asynchronous database methods first, and then make your API method asynchronous if it calls them.
Generally, it's best to start at the lowest-level calls and make those use await. FirstOrDefaultAsync, AnyAsync, SaveChangesAsync, etc. Anything doing I/O can be changed to use await. Once GetUser is an asynchronous method (and should be called GetUserAsync), then make your GetUser action method use async/await.
I'm trying to understand this code that I just found in this link:
I'm curious of what's the difference when between using the asynchronous and synchronous method in the Web API:
Asynchronous:
[HttpGet("{id}", Name = "GetBook")]
public async Task<IActionResult> GetBookWithBookCovers(Guid id)
{
var bookEntity = await _booksRepository.GetBookAsync(id);
if (bookEntity == null)
{
return NotFound();
}
// get bookcovers
var bookCovers = await _booksRepository.GetBookCoversAsync(id);
// map book & covers into one BookWithCovers
var mappedBook = _mapper.Map<BookWithCovers>(bookEntity);
return Ok(_mapper.Map(bookCovers, mappedBook));
}
Synchronous:
[HttpGet("{id}", Name = "GetBook")]
public IActionResult GetBookWithBookCovers(Guid id)
{
var bookEntity = _booksRepository.GetBook(id);
if (bookEntity == null)
{
return NotFound();
}
// get bookcovers
var bookCovers = _booksRepository.GetBookCovers(id);
// map book & covers into one BookWithCovers
var mappedBook = _mapper.Map<BookWithCovers>(bookEntity);
return Ok(_mapper.Map(bookCovers, mappedBook));
}
If there is a long running query in one of the codes of these two methods, what will be the behavior in the network console of browser?
Is the asynchronous method going to return a status code 202 while the query is running? or it will error out and saying like query timeout?
As Ian Kemp said "async/await ... has no effect on the HTTP protocol".
Client perspective
There is not difference. The same OK status code would return in both cases if no exception would occur during the request processing.
Sync or Async processing should be considered as an implementation detail. If you would have a OpenAPI documentation (a.k.a Swagger) then the two methods would look exactly the same.
Server perspective
Your ASP.NET WebAPI would not return anything to the caller until it reaches the end of the Controller's Action.
The await keyword says:
There is possibly a long-running operation.
The executing Thread can't move on to the next statement, because it relies on the result of the async operation.
Because the Thread can't do anything with this request, it would make sense to return to the ThreadPool and assign a new job to it (for example another request) until the async operation is running.
When that async operation is finished the ThreadPool will be notified and it will schedule the remaining of the Controller's Action to the appropriate Thread.
The async/await was designed (primarily) to support non-blocking async I/O operations. That means while the network driver handles the I/O request until that time the computation executors (Threads) could work on other things.
So in short, async/await gives you scalability (bigger throughput) for server applications.
I want to run a method asynchronously from my web api code but I am not getting the desired behavior.
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
I have tried various combination of calls with await and async but not getting any success still.
I might not be understanding the concept of async/await correctly.
Can you please let me know what's the mistake I am making?
My controller code is below
[HttpGet("{id}")]
public string Get(int id)
{
PracticeAsync p = new PracticeAsync();
p.LongCallMethod();
return "Success";
}
The code for the class PracticeAsync is below:
public class PracticeAsync
{
public async Task LongCallMethod()
{
var x = await CallThis();
}
public async Task<dynamic> CallThis()
{
Thread.Sleep(10000); //DB call
return "done";
}
}
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
That's not how async works.
You'll need to use SignalR or a proper distributed architecture. Specifically, your webapp should place its work into a reliable queue, and have an independent service read from that queue and do the work. ASP.NET was designed to serve web requests, and has severe reliability limitations if you try to force it to do otherwise.
I've just, for a rough draft, converted a whole lot of data access methods to async using the following pattern, and it looks too simple to be good enough for later iterations. How safe is it, what is missing, and how should I be doing it?
The service that provides long-running calls:
private class UserService
{
public IdentityUser GetById(int id)
{
...
}
}
private UserService _userService = new UserService();
The original synchronous method:
public IdentityUser GetById(int id)
{
return _userService.GetById(id);
}
My fantastic new async method:
public async Task<IdentityUser> GetByIdAsync(int id)
{
await Task.Run(() => _userService.GetById(id));
}
You should not make "fake async" methods like this:
public async Task<IdentityUser> GetByIdAsync(int id)
{
await Task.Run(() => _userService.GetById(id));
}
The reason I call it "fake async" is because there is nothing intrinsically async about the operation. In this case, you should have only the synchronous method. If a caller wants to make it async by using Task.Run, he can do that.
When is something intrinsically async? When you make a request to a web service or a database, for example, between sending the request and receiving the response there is a waiting period - the request is an intrinsically async operation. To avoid blocking the calling thread, use async-await.
Technically, that works, but it works by creating a new thread to perform a synchronous operation, which itself is wrapping and blocking on an inherently asynchronous operation. That means you're not getting some of the biggest benefits of going async in the first place.
The right way is to go asynchronous all the way. Whereas right now you probably have something like this:
private class UserService
{
public IdentityUser GetById(int id)
{
return mContext.Users.Single(u => u.Id == id);
}
}
... you should now create an async version:
private class UserService
{
public async Task<IdentityUser> GetByIdAsync(int id)
{
return await mContext.Users.SingleAsync(u => u.Id == id);
}
}
Usage:
public async Task<IdentityUser> GetByIdAsync(int id)
{
return await _userService.GetByIdAsync(id);
}
Supposing, of course, that your underlying framework supports asynchronous methods like SingleAsync() for inherently asynchronous operations, this will allow the system to release the current thread while you wait for the database operation to complete. The thread can be reused elsewhere, and when the operation is done, you can use whatever thread happens to be available at that time.
It's probably also worth reading about and adopting these Best Practices. You'll probably want to use .ConfigureAwait(false) anywhere that you're not accessing contextual information like sessions and requests, for example.
This answer assumes, of course, that GetById is inherently asynchronous: you're retrieving it from a hard drive or network location or something. If it's calculating the user's ID using a long-running CPU operation, then Task.Run() is a good way to go, and you'll probably want to additionally specify that it's a long-running task in the arguments to Task.Run().
Task.Run () should only be used for CPU-bound work. Don't quite remember why though.
Try to make a GetByIdAsync () method instead, that ultimately calls an async resource.
I have MVC 4.0 application targated at targetFramework="4.5".
I have to basically convert the existing functionality of file processing from synchronous to asynchronous (so that for large file user don't have to wait for other task).
My code is
[HttpPost]
public async Task<ActionResult> FileUpload(HttpPostedFileBase fileUpload)
{
Coreservice objVDS = new Coreservice ();
//validate the contents of the file
model =objVDS. ValidateFileContents(fileUpload);
// if file is valid start processing asynchronously
await Task.Factory.StartNew(() => { objVDS.ProcessValidFile(model); }, CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
return view();
}
Basically I want to call a asynchronous method which is in services which does database operations( diffrent project).
I want asynchronous process to have access to the context in services methods. Thats why I am using
TaskScheduler.FromCurrentSynchronizationContext() in Task.Factory.StartNew().
The service method is like following in which, based on file type, a second service is getting called for data operations
public async task ProcessValidFile(fileProcessDataModel model)
{
employeeWorkedDataservice service =new employeeWorkedDataservice()
await Task.Factory.StartNew(() =>
{
service .ProcessEmployeeDataFile(model.DataSetToProcess, OriginalFileName, this, model.Source);
},
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
}
ProcessEmployeeDataFile returns void and its not asynchronous method.
When the code above is executed it does not return to controller untill it completes the data processing. I think that I am missing something here.
Please guide me to solution.
Thanks,
Amol
Looks like you've misunderstood how await works.
Read this https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_WhatHappensUnderstandinganAsyncMethod
Setting something running in a task will allow it to run asynchronously so you can do something else while it's running.
When you need the result to continue, you use the await keyword.
By creating your task an immediately awaiting it, you're instantly blocking until the task resolves; making it effectively synchronous.
If you're happy to return to your view without waiting for processing to complete, I don't think you need await at all, since at no point do you want to wait for the result of the operation.
public task ProcessValidFile(fileProcessDataModel model)
{
employeeWorkedDataservice service =new employeeWorkedDataservice()
return Task.Factory.StartNew(() =>
{
service.ProcessEmployeeDataFile(model.DataSetToProcess, OriginalFileName, this, model.Source);
},
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
}
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase fileUpload)
{
Coreservice objVDS = new Coreservice ();
//validate the contents of the file
model =objVDS. ValidateFileContents(fileUpload);
// if file is valid start processing asynchronously
// This returns a task, but if we're not interested in waiting
// for its results, we can ignore it.
objVDS.ProcessValidFile(model);
return view();
}
Regarding your comments:
I would seriously consider not passing your controller to your service, or having your service rely on the session and context since you're tightly coupling your business logic to your API controller.
Get the bits you need from the controller while you're in it and pass them to your service.
I have to basically convert the existing functionality of file processing from synchronous to asynchronous (so that for large file user don't have to wait for other task).
That's not what async does; as I describe on my blog, async does not change the HTTP protocol.
What you want is some form of "fire and forget" on ASP.NET. I have another blog post that covers a few solutions. Note that using Task.Factory.StartNew is the most dangerous of all these solutions.
The best (read: most reliable) solution is to use a proper distributed architecture: your ASP.NET app should create a description of the work to be done and place that in a reliable queue (e.g., MSMQ); then have an independent backend (e.g., Win32 service) that processes the queue. This is complex, but much less error-prone than attempting to force ASP.NET to do something it was never meant to do.