using await inside another await - c#

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.

Related

Nested async & await in Web API application

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.

Asynchronous Controllers in Web Api

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.

Correct way to write async / await services in ServiceStack

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.

Correct way to use HttpContext.Current.User with async await

I am working with async actions and use the HttpContext.Current.User like this
public class UserService : IUserService
{
public ILocPrincipal Current
{
get { return HttpContext.Current.User as ILocPrincipal; }
}
}
public class ChannelService : IDisposable
{
// In the service layer
public ChannelService()
: this(new Entities.LocDbContext(), new UserService())
{
}
public ChannelService(Entities.LocDbContext locDbContext, IUserService userService)
{
this.LocDbContext = locDbContext;
this.UserService = userService;
}
public async Task<ViewModels.DisplayChannel> FindOrDefaultAsync(long id)
{
var currentMemberId = this.UserService.Current.Id;
// do some async EF request …
}
}
// In the controller
[Authorize]
[RoutePrefix("channel")]
public class ChannelController : BaseController
{
public ChannelController()
: this(new ChannelService()
{
}
public ChannelController(ChannelService channelService)
{
this.ChannelService = channelService;
}
// …
[HttpGet, Route("~/api/channels/{id}/messages")]
public async Task<ActionResult> GetMessages(long id)
{
var channel = await this.ChannelService
.FindOrDefaultAsync(id);
return PartialView("_Messages", channel);
}
// …
}
I have the code recently refactored, previously I had to give the user on each call to the service.
Now I read this article https://www.trycatchfail.com/2014/04/25/using-httpcontext-safely-after-async-in-asp-net-mvc-applications/ and I’m not sure if my code still works.
Has anyone a better approach to handle this? I don’t want to give the user on every request to the service.
As long as your web.config settings are correct, async/await works perfectly well with HttpContext.Current. I recommend setting httpRuntime targetFramework to 4.5 to remove all "quirks mode" behavior.
Once that is done, plain async/await will work perfectly well. You'll only run into problems if you're doing work on another thread or if your await code is incorrect.
First, the "other thread" problem; this is the second problem in the blog post you linked to. Code like this will of course not work correctly:
async Task FakeAsyncMethod()
{
await Task.Run(() =>
{
var user = _userService.Current;
...
});
}
This problem actually has nothing to do with asynchronous code; it has to do with retrieving a context variable from a (non-request) thread pool thread. The exact same problem would occur if you try to do it synchronously.
The core problem is that the asynchronous version is using fake asynchrony. This inappropriate, especially on ASP.NET. The solution is to simply remove the fake-asynchronous code and make it synchronous (or truly asynchronous, if it actually has real asynchronous work to do):
void Method()
{
var user = _userService.Current;
...
}
The technique recommended in the linked blog (wrapping the HttpContext and providing it to the worker thread) is extremely dangerous. HttpContext is designed to be accessed only from one thread at a time and AFAIK is not threadsafe at all. So sharing it among different threads is asking for a world of hurt.
If the await code is incorrect, then it causes a similar problem. ConfigureAwait(false) is a technique commonly used in library code to notify the runtime that it doesn't need to return to a specific context. Consider this code:
async Task MyMethodAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
var context = HttpContext.Current;
// Note: "context" is not correct here.
// It could be null; it could be the correct context;
// it could be a context for a different request.
}
In this case, the problem is obvious. ConfigureAwait(false) is telling ASP.NET that the rest of the current method does not need the context, and then it immediately accesses that context. When you start using context values in your interface implementations, though, the problem is not as obvious:
async Task MyMethodAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
var user = _userService.Current;
}
This code is just as wrong but not as obviously wrong, since the context is hidden behind an interface.
So, the general guideline is: use ConfigureAwait(false) if you know that the method does not depend on its context (directly or indirectly); otherwise, do not use ConfigureAwait. If it's acceptable in your design to have interface implementations use the context in their implementation, then any method that calls an interface method should not use ConfigureAwait(false):
async Task MyMethodAsync()
{
await Task.Delay(1000);
var user = _userService.Current; // works fine
}
As long as you follow that guideline, async/await will work perfectly with HttpContext.Current.
Async is fine. The problem is when you post the work to a different thread. If your application is setup as 4.5+, the asynchronous callback will be posted in the original context, so you'll also have the proper HttpContext etc.
You don't want to access shared state in a different thread anyway, and with Tasks, you rarely need to handle that explicitly - just make sure you put all your inputs as arguments, and only return a response, rather than reading or writing to a shared state (e.g. HttpContext, static fields etc.)
There is no problem, if your ViewModels.DisplayChannel is a simple object without additional logic.
A problem may occur, if the result of your Task references to "some context objects", f.e. to HttpContext.Current. Such objects are often attached to the thread, but entire code after await may be executed in another thread.
Keep in mind, that UseTaskFriendlySynchronizationContext doesn't solve all your problems. If we are talking about ASP.NET MVC, this setting ensures that Controller.HttpContext contains correct value as before await as after. But it doesn't ensure that HttpContext.Current contains correct value, and after await it still can be null.

Wraping sync API into Async method

My MVC application consumes a library and some methods of this library call WCF service internally. All methods exposed from this DLL are sync (none of them return Task or Task) and since we don't own that assembly, it is not possible to convert them into Async API.
However, because these methods call WCF service, they are network bound (so ideally they should be async).
I want to use async controller actions in my MVC application to make it more scalable. My question is how to make the entire method pipeline await able when one method is sync in nature.
Async action --> await async method --> await async method 2 --> sync method from library?
Should I use TaskCompletionSource or Task.FromResult to wrap the library method call?
Also, if I use above approach, will my code more scalable than sync version?
My question is how to make the entire method pipeline await able when one method is sync in nature.
You can't. The only solution is to rewrite the dll.
Should I use TaskCompletionSource or Task.FromResult to wrap the library method call?
Neither.
Also, if I use above approach, will my code more scalable than sync version?
No. It will be slightly less scalable.
TaskCompletionSource<T> is a way to create a puppet Task, which can complete at any point you like, and can make it fault at any point you like. This means, this would ideal in your case since you have no control over the API method, which you are trying to consume. Following example will give you a head start.
public class HomeController : Controller
{
public async Task<ActionResult> Index()
{
ViewBag.Message = await ProcessRequest();
return View();
}
//TResult -> can be of any built-in or custom type that you should decide.
Task<TResult> ProcessRequest()
{
// Make a TaskCompletionSource so we can return a puppet Task
TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
// Call your sync API method
SyncAPI syncApi = new SyncAPI();
// Call api method and set the result or exception based on the output from the API //method.
tcs.SetResult(TResult);
// Return the puppet Task, which isn't completed yet
return tcs.Task;
}
}

Categories