I'm trying to create a service to get all my boxes from the database like this :
[HttpGet]
[Route("GetBoxes/")]
[ResponseType(typeof(ResultQuery))]
public async Task<IHttpActionResult> GetBoxes()
{
try
{
var boxes = db.Boxes.ToList<Box>();
foreach (Box in boxes)
{
status.Add(GetBox(box));
}
return Ok(ConvertToResultQuery(boxes));
}
catch (Exception e)
{
return InternalServerError(e);
}
}
public GenericBox GetBox(Box box)
{
try
{
//Do a lot of stuff with the database
return genericBox;
}
catch (Exception e)
{
return null;
}
}
public static ResultQuery ConvertToResultQuery(object result)
{
return new ResultQuery(result);
}
Where ResultQuery has just one object attribute containing the result of my service.
The service is simple but for some reason it gives me this error when I try it in postman :
An asynchronous module or handler completed while an asynchronous operation was still pending.
VisualStudio also gives me a warning advising to use await but I don't understand where I should put it.
Your GetBoxes method is an async method, but your GetBox is not.
You say that you are doing db work inside the GetBox method but everything in that method is running synchronously. Consider changing the signature of GetBox to:
public async Task<GenericBox> GetBox(Box box)
{
try
{
//Do a lot of stuff with the database
//'await' database calls here
return genericBox;
}
catch (Exception e)
{
return null;
}
}
Then in your GetBoxes method change your foreach to a Task.WhenAll() instead:
var result = await Task.WhenAll(boxes.Select(x => GetBox(x)));
The result variable will be a Task
If you do not want to mess with Task.WhenAll(), you can simply await the GetBox method inside your loop:
status.Add(await GetBox(box));
Related
I have a problem with async/await in C#, i need it to get some object called Trades, after i get it, it needs to SAVE it. Problem is, with async/await, it is doing the SAVE first, and then go and get my trade objects. How do i ensure i get the objects first, and then does the saving.... here is my code...
private async void OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
public async Task<int> OnSaveTrades()
{
foreach (var trade in mmTrades)
{
await ExchangeServiceInstance.OnInsertDoneTrade(trade);
}
return mmTrades.Count;
}
Any ideas guys? Thanks!
The problem is your OnRefresh method. Because the return type is void the method is not awaited [Check out this answer]. In addition you dont even try to await for the method inside your delegate
Changing the method to the following:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
And await this method inside your delegate, should solve your problem:
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
await OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
The use of (Action)async is basically the same as async void, and async void is almost always a mistake. Specifically, the consumer cannot know the outcome (unless it faults synchronously). The dispatcher here isn't really thinking of async.
If we assume that you must use the dispatcher here, perhaps a workaround might be to use something like a SemaphoreSlim (or maybe a TaskCompletionSource<something>) that you signal at the end of your async work (even in the exception case), and then await that; untested, but:
var tcs = new TaskCompletionSource<bool>();
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
try {
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
tcs.TrySetResult(true);
} catch (Exception ex) {
tcs.TrySetException(ex);
}
});
await tcs.Task; // ensure the async work is complete
await OnSaveTrades();
First of all, you are using the async void pattern a lot. This is really bad practice for a number of reasons. You should stop doing that.
The problem here is that OnRefresh is again an async void method that can't be awaited but should be:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
In your OnSignalReceived method change the call to OnRefresh(); to await OnRefresh();
I try to test this structure but it never works.
I believe I have misunderstood it or lack knowledge in concurrency.
Please light me to the correct direction.
I call a save method but this never saves.
My code :
public async Task<MyObject> GetMyObject_ById(int id)
{
var responseDto = await this.RestApi.QueryMyObject_ById(id).ConfigureAwait(false);
if (responseDto != null)
{
return this.mapper.Map<MyObject>(responseDto);
}
else
{
return null;
}
}
public async Task<MyObject> UpdateMyObject(int id, MyObject updatevalue)
{
var dto = this.mapper.Map<MyObjectDto>(updatevalue);
var updateinfo = await this.RestApi.Update(id, dto).ConfigureAwait(false);
return this.mapper.Map<MyObject>(updateinfo);
}
private void Save()
{
foreach (MyObject pb in this.ListToSave)
{
this.SaveValue(pb.Id, pb.Status));
}
}
private async Task<MyObject> SaveValue(int id,string status)
{
var info = this.GetMyObject_ById(id).Result;
info.Status = status;
return await this.RestApi.UpdateMyObject(id, info).ConfigureAwait(false);
}
Just to summarize the comments. You should replace this.GetMyObject_ById(id).Result;
with await this.GetMyObject_ById(id); to avoid blocking. .Result and .Wait() should be avoided since they can cause deadlocks.
You probably want your save method to look like:
private async void Save()
{
try
{
foreach (MyObject pb in this.ListToSave)
{
await this.SaveValue(pb.Id, pb.Status));
}
}
catch(Exception e){
// handle exception
}
}
or
private async Task Save()
{
foreach (MyObject pb in this.ListToSave)
{
await this.SaveValue(pb.Id, pb.Status));
}
}
When using async methods you should always have some way to handle the result, even if the result might be an exception. This also executes each save call after the previous has completed, this is typically not a bad idea since it helps avoid threading issues.
I am taksed to introduce exception logging in a layer of middleware. From top to bottom of this middleware the calls are as follows:
//In layer C
public async Task<List<Foo>> GetFoo(GetFooRequest request)
{
return await _repository.GetFooAsync(request);
}
//In layer D
public async Task<List<Foo>> GetFooAsync(GetFooRequest request)
{
return await _context.Foo.Where(x=> x.FooId=request.FooID).ToListAsync();
}
I would like to log in Layer C, however, Task returns a System.Void, as such the compiler complains about the code below. I understand why the code below fails but I am having problems finding a solution pattern or practice of logging in layer C.
//In layer C
public async Task<List<Foo>> GetFoo(GetFooRequest request)
{
try
{
return await _repository.GetFooAsync(request);
}
catch(Exception e)
{
base.LogException(e) //<- Not all code paths return a value
}
}
Is there a way I can create a class that Invokes methods and do logging there, such as return await LogInvoker.Invoke(_repository.GetFooAsync...)? Or does this require refactoring the current flow between the layers?
You've got to do something at the end of the catch block. You mention in the question comments that you'd be prepared to return an empty list if something goes wrong:
public async Task<List<Foo>> GetFoo(GetFooRequest request)
{
try
{
return await _repository.GetFooAsync(request);
}
catch(Exception e)
{
base.LogException(e);
return new List<Foo>();
}
}
or rethrow the exception, if that makes sense to your application:
public async Task<List<Foo>> GetFoo(GetFooRequest request)
{
try
{
return await _repository.GetFooAsync(request);
}
catch(Exception e)
{
base.LogException(e);
throw;
}
}
I am trying to create the async task for the already existing code in my project for the database connection using EF 6.
I have created async task and it works fine, you can refer Using Async Task section for the code. But I want to rewrite The existing code of the project section as async task to maintain the consistency in the project.
Using Async Task: The below code works fine.
public static async Task<Student> InsertAsync(Student student)
{
try
{
using(PracticeContext context = new PracticeContext())
{
Repository<Student> repository = new Repository<Student>(context);
return await repository.InsertAsync(student);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
The existing code of the project:
I want to implement the below code as async task for both the Insert() and Execute() methods. So, that the data will be added to the database without holding the UI for the long time and make the project more user friendly.
Please suggest or provide the async implementation of the below codes.
public static Student Insert(Student student)
{
try
{
return Execute<Student, Student>((repository) => {
return repository.Insert(student);
});
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
private static TResult Execute<TResult, T>(Func<Repository<T>, TResult> func) where T: class
{
using(PracticeContext context = new PracticeContext())
{
try
{
return func(new Repository<T>(context));
}
catch(Exception ex)
{
Console.WriteLine(ex);
throw new Exception("Error Occured.");
}
}
}
I would be glad to add more stuffs if required to make the questions more accurate and understandable.
The first thing you do is change the lowest-level call to use the asynchronous version and use async in its enclosing method/lambda. Then let the async grow from there. So the first step would be:
return Execute<Student, Student>(async (repository) => {
return await repository.Insert(student);
});
This code then requires Execute to allow asynchronous delegates. At this step, we probably want other code to continue using the synchronous Execute, so we can copy/paste it and make the new overload take an asynchronous delegate:
private static async Task<TResult> Execute<TResult, T>(Func<Repository<T>, Task<TResult>> func) where T: class
{
using(PracticeContext context = new PracticeContext())
{
try
{
return await func(new Repository<T>(context));
}
catch(Exception ex)
{
Console.WriteLine(ex);
throw new Exception("Error Occured.");
}
}
}
Now that the asynchronous Execute returns a Task<T>, we then need to await it back in the calling method:
return await Execute<Student, Student>(async (repository) => {
return await repository.Insert(student);
});
which then makes the calling method asynchronous as well:
public static async Task<Student> InsertAsync(Student student)
{
try
{
return await Execute<Student, Student>(async (repository) => {
return await repository.Insert(student);
});
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
}
New to async await integration in C# 5. I'm working with some basic Task based methods to explore async await and the TPL. In this example below I'm calling a web service with a timeout of 5 seconds. If the timeout expires it should throw an exception so I can return false from the method. However, the timeout never occurs, or maybe it does but the Task never returns.
public static Task<bool> IsConnectedAsync()
{
return Task.Run(() =>
{
try
{
using (WSAppService.AppService svc = new NCSoftware.Common.WSAppService.AppService(GetServiceUrl(WebService.app)){Timeout = 5000})
{
return svc.PingB();
}
}
catch (Exception ex)
{
Logger.LogException(ex.Message, ex, "IsConnectedAsync");
}
return false;
});
}
If you could please help with how to properly handle this so that if the timeout occurs or even better, an exception occurs, the Task does return.
In general, you shouldn't use Task.Run if you're wrapping async services. Since this is a service reference, you should be able to expose an async method (returning Task) directly from the service, in which case you could use:
public async static Task<bool> IsConnectedAsync()
{
try
{
using (WSAppService.AppService svc = new NCSoftware.Common.WSAppService.AppService(GetServiceUrl(WebService.app)){Timeout = 5000})
{
return await svc.PingBAsync();
}
}
catch (Exception ex)
{
Logger.LogException(ex.Message, ex, "IsConnectedAsync");
}
return false;
}
If you must wrap via Task.Run (again, this is not suggested, as it's turning synchronous code into async via the thread pool, which is typically better handled by the user at the top level), you could do:
public async static Task<bool> IsConnectedAsync()
{
try
{
return await Task.Run(() =>
{
using (WSAppService.AppService svc = new NCSoftware.Common.WSAppService.AppService(GetServiceUrl(WebService.app)){Timeout = 5000})
{
return svc.PingB();
}
}
}
catch (Exception ex)
{
Logger.LogException(ex.Message, ex, "IsConnectedAsync");
return false;
}
}