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.
Related
I am developing a web api and I have some async methods from EF. All the examples I read on the internet show simple calls or snipets, but not what I am looking for...so, this is my question:
I have this method in my repository class:
public async Task GuardarLibro(Book book)
{
var dbLibro = _libroConverter.Convert(libro);
using (_migraPleContext)
{
_migraPleContext.Libro.Add(dbLibro);
await _migraPleContext.SaveChangesAsync();
}
}
Then I have another class that calls my repository...since, the method from my repository is async, I call it this way:
var libroDb = _libroConverter.Convert(libro);
await _libroRepository.GuardarLibro(libroDb);
My question is, if this approach is correct. I am using an await in my handler class and another await in my repository class, and I am not sure if this is a good practice or if it has a performance impact.
This is one correct way in which async/await can be used.
You may consider also calling .ConfigureAwait(false); on each awaitable Task if you do not require the context to captured.
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");
}
Say I have two scenarios:
1) WebApi Controller
[System.Web.Http.HttpPost]
[System.Web.Http.AllowAnonymous]
[Route("api/registerMobile")]
public async Task<HttpResponseMessage> RegisterMobile(RegisterModel model)
{
var registerResponse = await AuthUtilities.RegisterUserAsync(model, _userService, User);
if (registerResponse.Success) {
var response = await _userService.GetAuthViewModelAsync(model.Username, User);
return Request.CreateResponse(HttpStatusCode.OK, new ApiResponseDto() { Success = true, Data = response });
}
else {
return Request.CreateResponse(HttpStatusCode.OK, registerResponse);
}
}
2) MVC Controller
[Route("public")]
public async Task<ActionResult> Public()
{
if (User.Identity.IsAuthenticated)
{
var model = await _userService.GetAuthViewModelAsync(User.Identity.Name);
return View("~/Views/Home/Index.cshtml", model);
}
else
{
var model = await _userService.GetAuthViewModelAsync(null);
return View("~/Views/Home/Index.cshtml", model);
}
}
I've been reading up on when I should use ConfigureAwait and it seems like I should use ConfigureAwait(false) on ALL of my async calls that are not tied directly to the UI. I don't know what that means though... should I be using .ConfigureAwait(false) on all of the above await calls?
I'm looking for some unambiguous guidelines around when exactly I should be using it.
This question is NOT the same as the Best practice to call ConfigureAwait for all server-side code - I am looking for a straightforward answer on the use-case for this method in the context of WebApi and MVC, not as general C#.
it seems like I should use ConfigureAwait(false) on ALL of my async calls that are not tied directly to the UI.
Not quite. That guideline doesn't make sense here, since there is no UI thread.
The parameter passed to ConfigureAwait is continueOnCapturedContext, which explains more clearly the scenario. You want to use ConfigureAwait(false) whenever the rest of that async method does not depend on the current context.
In ASP.NET 4.x, the "context" is the request context, which includes things like HttpContext.Current and culture. Also - and this is the undocumented part - a lot of the ASP.NET helper methods do depend on the request context.
(Side note: ASP.NET Core no longer has a "context")
should I be using .ConfigureAwait(false) on all of the above await calls?
I haven't heard any firm guidance on this, but I suspect it's OK.
In my own code, I never use ConfigureAwait(false) in my controller action methods, so that they complete already within the request context. It just seems more right to me.
If there's no actual context in a ASP.NET Core application, it should do no harm nor good to add .ConfigureAwait(false) to your awaitable methods into controllers.
However, if there is a chance that eventually in the future, for whatever reason, there's something like a context to be taken into account as in ASP.NET 4, that would be a different story. We could not risk running in a different context, unless we don't give a damn about it (in which case we could use whatever thread is available for processing, thus possibly improving performance).
My choice here is to add ConfigureAwait(false) even if it's not used.
You may use ConfigureAwait on public action MVC Controller, it help to prevent deal lock if your _userService.GetAuthViewModelAsync keeps waiting.
it cloud raise deadlock if async service keeps await so by may block httpcontext of UI.
Have look below link to understand this case:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Using ConfigureAwait(false) in controllers does not sound good to me as it will make main thread wait until the operation is finished. The best I figured out is to use it in your Service/Business layer and Persistance layer.
I have very basic fundamental doubt regarding asynchronous Web API programming. I want to make call to SaveCaseSearch in my controller asynchronously. But the call passes through various layers of DAL and eventually calls DB.
Should those consecutive calls also be made asynchronous ?
I am very new to the world of async so I might already have made some mistakes. Just correct me if anything seems wrong.
So for the controller , I am doing something like the below :
/*Create API for Case*/
[HttpPost]
[Route("createcase")]
public IHttpActionResult PostCreateCase([FromBody] ARC.Donor.Business.Case.CreateCaseInput CreateCaseInput)
{
ARC.Donor.Service.Case.CaseServices cs = new ARC.Donor.Service.Case.CaseServices();
var searchResults = cs.createCase(CreateCaseInput);
List<CreateCaseOutput> searchOutputResults = (List<CreateCaseOutput>)searchResults;
if (!string.IsNullOrEmpty(searchOutputResults.ElementAt(0).o_case_seq.ToString()))
SaveCaseSearchDetails(SaveSearchInput); /*This should be called asynchronously*/
return Ok(searchResults);
}
This
SaveCaseSearchDetails
now needs to be called in async mode . So I have written :
[HttpPost]
public async Task<IHttpActionResult> SaveCaseSearchDetails([FromBody] ARC.Donor.Business.SaveSearchInput SaveSearchInput)
{
ARC.Donor.Service.Case.CaseServices cs = new ARC.Donor.Service.Case.CaseServices();
var searchResults = await cs.saveCaseSearchDetails(SaveSearchInput);
}
Then if that is correct
should the consecutive calls be async too ?
For now they are
public IList<Entities.Case.SaveCaseSearchOutput> saveCaseSearch(ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput)
{
Repository rep = new Repository();
string strSPQuery = string.Empty;
List<object> listParam = new List<object>();
SQL.CaseSQL.getCreateCaseParameters(SaveCaseSearchInput, out strSPQuery, out listParam);
var AcctLst = rep.ExecuteStoredProcedure<Entities.Case.SaveCaseSearchOutput>(strSPQuery, listParam).ToList();
return AcctLst;
}
Is
SQL.CaseSQL.getCreateCaseParameters
method needs to be called in async manner ?
But in that case the immediate next line
rep.ExecuteStoredProcedure
can't execute successfully right ? Because strSPQuery comes from the previous line itself ?
I am thinking in a wrong way ? Please correct me .
Should those consecutive calls also be made asynchronous?
Yes.
SaveCaseSearchDetails now needs to be called in async mode
That's the hard way of doing it.
A much more natural approach is to start at the other end. Whatever part of your code is actually executing the database query should be made asynchronous first. Then you call it using await, which makes those methods async, so they should be called with await, etc., until you finally reach your controller action which is the last thing to be made asynchronous.
actually the problem I am facing is SaveCaseSearchDetails(SaveSearchInput) in PostCaseCreate method needs to be called somewhat async because we don't want to wait for return Ok(searchResults)
Ah, that's a totally different question. You want to return early. Async will not help you do this; as I explain on my blog (and in an MSDN article on async ASP.NET), async does not change the HTTP protocol.
There are a few approaches to returning early or "fire and forget" on ASP.NET that I describe on my blog. However, ASP.NET was not designed for this scenario, so you need to tread carefully. The only fully reliable solution is a properly distributed architecture.
You cannot call SQL.CaseSQL.getCreateCaseParameters in an async manner (with await) since it uses the out keyword which isn't available for async metods.
If you want your DB call to happen async you'll have to find a DB method that you can await. Then you can change the saveCaseSearch method to also be async and await it from your controller method.
I m trying to write an async service with ServiceStack and to me it seems that this feature is not really complete.
My questions:
1) How do you pass CancellationTokens in the service methods?
2) What about ConfigureAwait(false) in those methods? For example
public Task<SomeResponse> Get(SomeRequest request)
{
return _manager.ExecuteAsync(request).ConfigureAwait(false);
}
This doesnt compile.
3) Should we be marking such services with the async keyword and return Task to make them awaitable? For example this doesnt work (usage is silly but you get the point)
public async Task<SomeResponse> Get(SomeRequest request)
{
return await _manager.ExecuteAsync(request).ConfigureAwait(false);
}
Should we even be writing async services with ServiceStack? Is there a benefit or the current implementation defeats the purpose?
Thanks
If the methods don't accept cancellation tokens, then they weren't designed to be cancellable, and you can't cancel them.
You're not actually awaiting the task, so there's no await to configure. Just omit the ConfigureAwait since you have no await to configure.
There's no need to mark a method as async if you're not actually going to leverage any of the features of it or accomplish anything with it that isn't already done by just not doing that. It's not breaking anything other than making the code a tiny bit slower, but it's not adding anything either.
You can make an async request as normal using C# async/await, i.e:
var response = await client.GetAsync(requestDto);
Or if you prefer (or cannot use await), you can use Continuations on the returned Task<T>, e.g:
client.GetAsync(new Hello { Name = "World!" })
.Success(r => r => r.Result.Print())
.Error(ex => { throw ex; });
You can cancel an async request with:
client.CancelAsync();
This calls HttpWebRequest.Abort() behind the scenes.