Async await call does not return - c#

I have a problem, where i call an async method, and the call does not return back. I assume its a race of threads. How do I write this correctly?
This is where it starts. I first call an async method called "GetCachedValuesAsync"
public void OnNavigatingTo(NavigationParameters parameters)
{
Task.Run(async () =>
{
await GetCachedValuesAsync();
ClipRefernce = GenerateRefernce(clips);
});
}
Here is the method signature for GetCachedValueAsync
public async Task GetCachedValuesAsync()
{
try
{
clips = await BlobCache.LocalMachine.GetObject<List<Clip>>("clips");
}
catch (KeyNotFoundException ex)
{
clips = new List<Clip>();
}
}
I do not get the call returned from BlobCache, BlobCahce method is part of a library called akavache.
The code also does not hit: ClipRefernce = GenerateRefernce(clips);
I appreciate your help
Edit 1
This is GenerateRefernce method.
public string GenerateRefernce(List<Clip> clips)
{
string refernce = "";
if(clips.Count > 0)
{
var clip = clips.LastOrDefault();
refernce = String.Format("Ref {0:yyyy}/{1}",DateTime.Now , clip.ClipId + 1);
}
else{
refernce = String.Format("Ref {0:yyyy}/{1}", DateTime.Now, 1);
}
return refernce;
}

You need to remove the sync method from the Task.Run like this:
public void OnNavigatingTo(NavigationParameters parameters)
{
Task.Run(async () =>
{
await GetCachedValuesAsync();
});
ClipRefernce = GenerateRefernce(clips);
}
public async Task GetCachedValuesAsync()
{
try
{
clips = await BlobCache.LocalMachine.GetObject<List<Clip>>("clips");
}
catch (KeyNotFoundException ex)
{
clips = new List<Clip>();
}
}

Related

How to properly catch exceptions in multiple async method calls?

I have some async method:
public async Task<Object> MethodAsync()
{
return await MakeHttpRequestAsync();
}
I need to make multiple calls of this method. One of them can throw an exception. But I need to keep all possible returned Objects from other method calls that succeeded.
Option 1:
Task t1 = MethodAsync();
Task t2 = MethodAsync();
try
{
Task.WaitAll(new Task[]{t1,t2});
}
catch(Exception e)
{
...
}
//are t1 and t2 finished execution here with success or exception?
Option 2:
Task t1 = MethodAsync();
Task t2 = MethodAsync();
try
{
t1.Wait()
}
catch(Exception e)
{
...
}
try
{
t2.Wait()
}
catch(Exception e)
{
...
}
//what happens if t2 throws exception before t1 finished?
Any other options?
edit:
Thought about third option:
public async Task<Tuple<Object, Object>> MultipleAsyncCallsAsync(some arguments)
{
Object result1 = null, result2 = null;
try
{
result1 = await MethodAsync();
}
catch(Exception e)
{
}
try
{
result2 = await MethodAsync();
}
catch (Exception e)
{
}
return Tuple.Create(result1, result2);
}
edit #2:
Looks like third option is not working, but it's working this way:
public async Task<Tuple<object, object>> MultipleAsyncCallsAsync(some arguments)
{
object result1 = null, result2 = null;
Task<object> t1 = null, t2 = null;
t1 = Task.Run(()=> MethodAsync());
t2 = Task.Run(()=> MethodAsync());
try
{
result1 = await t1;
}
catch(Exception e)
{
}
try
{
result2 = await t2;
}
catch (Exception e)
{
}
return Tuple.Create(result1, result2);
}
Put the tasks in an array and inspect their status like this:
var t1 = MethodAsync();
var t2 = MethodAsync();
var tasks = new[] {t1, t2};
try
{
await Task.WhenAll(tasks);
}
catch
{
var failedTasks = tasks.Where(t => t.IsFaulted);
var allExceptions = failedTasks.Select(t => t.Exception?.Flatten());
}
var results = tasks.Where(t => t.IsCompletedSuccessfully).Select(t => t.Result);
What is does is it awaits all tasks and then uses the task status (using IsCompletedSuccessfully ect.) to get the results of all the tasks that did complete succesfully.
You can determine the failed tasks using IsFaulted and get their exception using the tasks Exception property.
If you want to catch/inspect the exception before the call to Task.WhenAll(..) is completed wrap the code inside MethodAsync in a try/catch:
public async Task<Object> MethodAsync()
{
try
{
..
}
catch(Exception ex)
{
//handle or throw
return null;
}
}
Or, if you cannot modify MethodAsync for some reason, you can wrap the method in a try/catch using this:
Func<Task<Object>, Task<Object>> TryExecute = new Func<Task<Object>, Task<object>>(async t =>
{
try
{
return await t;
}
catch (Exception ex)
{
//handle exception
return null;
}
});
and use it like this:
var t1 = TryExecute(MethodAsync());
var t2 = TryExecute(MethodAsyncF());
var tasks = new[] {t1, t2};
await Task.WhenAll(tasks);
Whenever there's a question about this kind of procedure ("call n methods, (a)wait for them all to complete, and then retrieve the results for each method and do something with them"), a better solution is almost always to create a higher-order method.
For example, if you want to do some kind of logging or something but otherwise ignore exceptions, then you can create a higher-order method like this:
public async Task<T> LogAndIgnoreExceptions(Task<T> task) where T : class
{
try
{
return await task;
}
catch (Exception ex)
{
Log(ex);
return null;
}
}
Then you can use Task.WhenAll in a very natural way:
var results = await Task.WhenAll(
LogAndIgnoreExceptions(MethodAsync()),
LogAndIgnoreExceptions(MethodAsync())
);
if (results[0] is not null)
{
T result = results[0];
}
else
{
// First call had an error.
}
Or, if you want to preserve the exception details and results, what you want is a little helper type like Try to enable railway programming:
var results = await Task.WhenAll(
Try.Create(MethodAsync()),
Try.Create(MethodAsync())
);
if (results[0].IsValue)
{
T result = results[0].Value;
}
else
{
Exception exception = results[0].Exception;
}

How to run backgroundservices on seperate thread?

I realized that background services blocks main thread and suddenly it makes latency in my main thread.I can't find useful resources about how to make backgroundservices to not make latency and block main thread.Any suggestions?
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork, null, 0, 10000);
Initialize().GetAwaiter();
return Task.CompletedTask;
}
private async void DoWork(object state)
{
try
{
//some logic
await testService.DoWorkAsync();
}
catch (Exception ex)
{
Log.Error(ex, "TestBackgroundService DoWork throws ");
}
}
private async Task Initialize()
{
while (true)
{
try
{
if (IsEnabled)
{
//some logic
await testService.PrintAsync();
IsEnabled = false;
}
else
{
//some logic
await testService.CloseAsync();
if (condition)
{
IsEnabled = true;
}
}
await Task.Delay(1000);
}
catch (Exception ex)
{
Log.Error($"ExecuteAsync throws {ex.ToString()}");
}
}
}
You have to use it the right way and I think scoped background task is what you want:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-3.1&tabs=visual-studio#consuming-a-scoped-service-in-a-background-task
Here you have a ExecuteAsync Method and you could use it like this:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
//your code
await DoWork(stoppingToken);
Task.Delay(1000);
}
}
If it is possible, you can create an Controller for the background jobs.
From your code, you can simply invoke the controller action using an HttpClient method.
private async Task ExecuteJobAsync(string jobName)
{
// background job
string uri = $"http://localhost:21454/api/jobs/{jobName}";
using (HttpClient client = new HttpClient())
{
using (HttpContent content = new StringContent(string.Empty, Encoding.UTF8, "application/json"))
{
using (HttpResponseMessage response = await httpClient.PostAsync(uri, content).ConfigureAwait(false))
{
}
}
}
}
Invoking background job:
private async Task Initialize()
{
while (true)
{
try
{
if (IsEnabled)
{
await ExecuteJobAsync("print");
IsEnabled=false;
}
else
{
//some logic
await ExecuteJobAsync("close");
if(condition){
IsEnabled=true;
}
}
await Task.Delay(1000);
}
catch (Exception ex)
{
Log.Error($"ExecuteAsync throws {ex.ToString()}");
}
}
}
Jobs controller:
[Route("api/jobs")]
public class JobsController : Controller
{
[HttpPost("print")]
public void PrintAction()
{
// code
}
[HttpPost("close")]
public void CloseAction()
{
// code
}
}

How to refactor this C# code

I have these functions
public async Task<List<Machine>> GetMachines()
{
await Initialize();
await SyncMachines();
return await machineTable.ToListAsync();
}
public async Task InsertMachines(List<Machine> machines)
{
await Initialize();
await Task.WhenAll(machines.Select(m => machineTable.InsertAsync(m)));
await SyncMachines();
}
I am writing a parent class to put these functions in, such that the functions getMachines() and InsertMachines() become getObject and InsertObject where the List<Machine> can be a list of any objects, so they can return and accept any type of list
How do I declare functions like this?
According to your description, I created my azure sync table class as follows, you could refer to it:
public class AzureCloudSyncTable<TModel> where TModel : class
{
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://{your-mobile-app-name}.azurewebsites.net"
);
private IMobileServiceSyncTable<TModel> syncTable = MobileService.GetSyncTable<TModel>();
#region Offline sync
private async Task InitLocalStoreAsync()
{
if (!MobileService.SyncContext.IsInitialized)
{
var store = new MobileServiceSQLiteStore("localstore.db");
store.DefineTable<TModel>();
await MobileService.SyncContext.InitializeAsync(store);
}
await SyncAsync();
}
private async Task SyncAsync()
{
await PushAsync();
await syncTable.PullAsync(typeof(TModel).Name, syncTable.CreateQuery());
}
private async Task PushAsync()
{
try
{
await MobileService.SyncContext.PushAsync();
}
catch (MobileServicePushFailedException ex)
{
if (ex.PushResult != null)
{
foreach (var error in ex.PushResult.Errors)
{
await ResolveConflictAsync(error);
}
}
}
}
private async Task ResolveConflictAsync(MobileServiceTableOperationError error)
{
//var serverItem = error.Result.ToObject<TModel>();
//var localItem = error.Item.ToObject<TModel>();
//// Note that you need to implement the public override Equals(TModel item)
//// method in the Model for this to work
//if (serverItem.Equals(localItem))
//{
// // Items are the same, so ignore the conflict
// await error.CancelAndDiscardItemAsync();
// return;
//}
//// Client Always Wins
//localItem.Version = serverItem.Version;
//await error.UpdateOperationAsync(JObject.FromObject(localItem));
// Server Always Wins
//await error.CancelAndDiscardItemAsync();
}
#endregion
#region public methods
public async Task<List<TModel>> GetAll()
{
await InitLocalStoreAsync();
await SyncAsync();
return await syncTable.ToListAsync();
}
public async Task Insert(List<TModel> items)
{
await InitLocalStoreAsync();
await Task.WhenAll(items.Select(item => syncTable.InsertAsync(item)));
await PushAsync();
}
#endregion
}
Additionally, for more details about Handling Conflict Resolution, you could refer to adrian hall's book here.

ReadAsMultipartAsync not works

I want know if anyone know because is happening this:
This not works:
[AcceptVerbs("POST")]
public void AddFile()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var streamProvider = new MultipartFormDataMemoryStreamProvider();
Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
{
....
});
}
But this if it works(is the the correct solution?):
[AcceptVerbs("POST")]
public Task AddFile()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var streamProvider = new MultipartFormDataMemoryStreamProvider();
return Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
{
....
});
}
In the first example, you are not processing the returned task from ReadAsMultipartAsync. The method immediately exits.
In the second example, you give the task to the base class, which handles the task for you and waits for it's execution.
If you do not want to return the task, e.g. if you want to do something after it finishes, you can mark your method as async and await the task like so:
[AcceptVerbs("POST")]
public async Task AddFile()
{
if (!Request.Content.IsMimeMultipartContent("form-data"))
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var streamProvider = new MultipartFormDataMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(streamProvider).ContinueWith(t =>
{
....
});
}

Passing exception from Task.Run to await properly and Debugger

This is the task, where the exception is being thrown.
public Task<SensorReading> ReadSensorsAsync(int cell)
{
return Task.Run(() => {
throw new ArgumentNullException();
...
This is the async method:
private async void TimerCallback(object state)
{
try
{
var tasksRead = Enumerable.Range(3, 35).Select(i => sensorReader.ReadSensorsAsync(i)).ToList();
await Task.WhenAll(tasksRead);
var r = tasksRead.Select(x => x.Result).ToList();
var taskRecordREsult = RecordReadingAsync(r).Result;
}
catch(Exception e)
{
// expecting to catch everything here
}
}
What I was expecting is that exception would be handled in await part of the code. However, I am getting unhandled exception in Visual Studio debugger.
Question - how to properly pass all kind of exception from Task.Run to awaitable part?
One possible solution is to extract your Task.Run lambda into a standalone method, and add the [DebuggerStepThrough] attribute to it. In theory (I haven't tested this), this will suppress the first exception in the debugger, and allow it to be caught later. It's not pretty, but it should do the trick.
try this program and see if you still get breaking..
its working for me
class Program
{
static void Main(string[] args)
{
new Program().TimerCallback();
}
public Task<string> ReadSensorsAsync(string cell)
{
return Task.Run(() =>
{
if(cell == null) throw new ArgumentNullException();
return cell;
});
}
public Task<string> RecordReadingAsync(IEnumerable<string> cell)
{
return Task.Run(() =>
{
return string.Join(",", cell);
});
}
public async void TimerCallback()
{
try
{
var tasksRead = new string[] { "1", null, "3" }.Select(s => ReadSensorsAsync(s));
var taskRecordResult = await RecordReadingAsync(await Task.WhenAll(tasksRead));
Debugger.Log(1, "test", taskRecordResult);
}
catch (Exception e)
{
//catches here
Debugger.Log(1, "test", e.Message ?? e.ToString());
}
}
}

Categories