I would like to know the proper way to handle exceptions in scenario like
---Updated code with solution---
var wt = new List<PendingSettlement>();
var ot = new List<PendingSettlement>();
var otTask = Task.Run(async () => ot = await LoadOtDataAsync().ConfigureAwait(false));
var wtTask = Task.Run(async () => wt = await LoadWtDataAsync().ConfigureAwait(false));
var tasks = new List<Task>
{
otTask, wtTask
};
try
{
await Task.WhenAll(tasks);
}
catch
{
run.WarningMessage = GetInnermostExceptionMessage(wtTask.Exception) + Environment.NewLine + GetInnermostExceptionMessage(otTask.Exception);
string GetInnermostExceptionMessage(Exception e)
{
if (e == null) return string.Empty;
_logger.LogError(e, e.Message);
while (e.InnerException != null) e = e.InnerException;
return e.Message;
}
}
Is there way to figure which inner exception corresponds to which task?
Store the tasks (e.g. var t1 = Task.Run(...);). Then, you can query the exception using t1.Exception. You can simply ignore the exception you get from done.Wait(); then. I'd do that by writing done.ContinueWith(_ => { }).Wait(); to avoid throwing and catching.
Related
I'm developing a Xamarin application. It's a glorified audio player. I created a background task for the UWP part which extends IBackgroundTask from Windows.ApplicationModel.Background.
using Windows.ApplicationModel.Background;
public sealed class BackgroundServiceManager : IBackgroundTask {
private IIpcNode m_node;//Sends/Receive message powered by LocalSettings
private BackgroundTaskDeferral m_deferral;
public void Run(IBackgroundTaskInstance taskInstance) {
DebugUtils.Log("BackgroundServiceManager.Run()");
m_deferral = taskInstance.GetDeferral();
m_services = new List<IBackgroundService> {
(m_playbackService = new PlaybackService()),
(m_smartLightService = new SmartLightsService())
};
this.RegisterServices();
taskInstance.Task.Completed += OnTaskCompleted;
taskInstance.Canceled += OnTaskCanceled;
//Listen to messages powered by LocalSettings
m_node.StartListening();
}
//...
}
I start the task using an application trigger. The background task lives in a separate project.
public async Task InitializeBackgroundTask() {
var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
localSettings.Values.Clear();
BackgroundExecutionManager.RemoveAccess();
var accessStatus = await BackgroundExecutionManager.RequestAccessAsync();
if (accessStatus == BackgroundAccessStatus.DeniedBySystemPolicy
|| accessStatus == BackgroundAccessStatus.DeniedByUser
|| accessStatus == BackgroundAccessStatus.Unspecified)
return;
UnregisterExistingTasks();
var builder = new BackgroundTaskBuilder() {
Name = BACKGROUND_TASK_NAME,
TaskEntryPoint = BACKGROUND_TASK_ENTRY_POINT,
};
var applicationTrigger = new ApplicationTrigger();
builder.SetTrigger(applicationTrigger);
var registration = (BackgroundTaskRegistration)null;
try {
registration = builder.Register();
}
catch (Exception ex) {
throw new Exception(string.Format("Unable to register {0} background task.", BACKGROUND_TASK_NAME), ex);
}
registration.Completed += OnBackgroundTaskCompleted;
registration.Progress += OnRegistrationProgress;
this.Node.StartListening();
var result = await applicationTrigger.RequestAsync();
if (result != ApplicationTriggerResult.Allowed)
throw new Exception("Unable to trigger background task.");
}
I have a background task declaration in my main UWP project. The task type is "general" and I provide the proper entry point.
Also, the Background Media Playback capability is checked.
The task works perfectly fine, but AudioGraph doesn't generate sounds on the background task. MediaPlayer does, however. I need AudioGraph as it allows for seamless audio looping.
Here's my AudioGraph test method. I created it to isolate AudioGraph-related code:
public static async Task TestAudioGraph(int toneFrequency) {
var audioFileInfo = await AudioUtils.CreateToneFile(toneFrequency);
var settings = new AudioGraphSettings(Windows.Media.Render.AudioRenderCategory.Media);
var createAudioGraphResult = await AudioGraph.CreateAsync(settings);
if (createAudioGraphResult.Status != AudioGraphCreationStatus.Success)
throw new Exception(createAudioGraphResult.Status.ToString());
var audioGraph = createAudioGraphResult.Graph;
var createDeviceOutputNodeResult = await audioGraph.CreateDeviceOutputNodeAsync();
if (createDeviceOutputNodeResult.Status != AudioDeviceNodeCreationStatus.Success)
throw new Exception(createDeviceOutputNodeResult.Status.ToString());
var deviceOutputNode = createDeviceOutputNodeResult.DeviceOutputNode;
var storageFile = await StorageFile.GetFileFromPathAsync(audioFileInfo.FileFullPath);
var createFileInputNodeResult = await audioGraph.CreateFileInputNodeAsync(storageFile);
if (createFileInputNodeResult.Status != AudioFileNodeCreationStatus.Success)
throw new Exception(createFileInputNodeResult.Status.ToString());
var fileInputNode = createFileInputNodeResult.FileInputNode;
fileInputNode.OutgoingGain = 1;
fileInputNode.LoopCount = Int32.MaxValue;
fileInputNode.AddOutgoingConnection(deviceOutputNode);
fileInputNode.Start();
audioGraph.Start();
await Task.Delay(3000);
}
Sending of sound test message from foreground:
public async Task TestSound() {
//Test sound on foreground first
await Task.Run(async () => await UWPUtils.TestAudioGraph(200));
var message = new UWPIpcMessage("TESTSOUND", null);
await this.Node.SendMessage(message, true);
}
Background's handling of sound test message:
m_node.Subscribe("TESTSOUND", async (message) => {
//Then test sound on background
await Task.Run(async () => await UWPUtils.TestAudioGraph(800));
return null;
});
Would you happen to know why AudioGraph doesn't work? Am I missing a setting or is this possible at all?
I look on the web and couldn't find examples or working samples, just hints that what I'm attempting is possible.
P-S: My task type is "general", because I found no way of triggering "audio" type of tasks.
Thank you
I am trying to make a parallel call to Elasticsearch index for multiple queries and aggregate the result, using Parallel.ForEach.
My code:
private static List<SearchResponse<dynamic>> SearchQueryInParallel(string indexName, string lang, string[] eQueries)
{
var result = new List<SearchResponse<dynamic>>();
var exceptions = new ConcurrentQueue<Exception>();
object mutex = new object();
try
{
Parallel.ForEach(eQueries,
() => new SearchResponse<dynamic>()
, (q, loopState, subList) =>
{
var x = LowlevelClient.Search<SearchResponse<dynamic>>(indexName, $"article_{lang}", q);
subList = x;
return subList;
}, subList =>
{
lock (result)
result.Add(subList);
}
);
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
exceptions.Enqueue(e);
}
}
if (exceptions.ToList().Any())
{
//there are exceptions, do something with them
//do something?
}
return result;
}
The problem I am facing is that sublist in the above case is long.
It gives me the following error:
Can not convert from SearchResponse to long.
The same thing is working when I used without multithreading, the code is:
var items = new List<dynamic>();
var searchResponse = lowLevelClient.Search<SearchResponse<dynamic>>(elasticIndexName, $"article_{languageCode.ToLowerInvariant()}", query);
foreach (var document in searchResponse.Body.Documents)
{
items.Add(document);
}
Any help, please? If somebody has any other way to achieve the parallel call and aggregating data from returned values would be greatly appreciated.
I am attempting to retrieve the names and phone number(s) of all contacts and show them into tableview in Xamarin.iOS. I have made it this far:
var response = new List<ContactVm>();
try
{
//We can specify the properties that we need to fetch from contacts
var keysToFetch = new[] {
CNContactKey.PhoneNumbers, CNContactKey.GivenName, CNContactKey.FamilyName, CNContactKey.EmailAddresses
};
//Get the collections of containers
var containerId = new CNContactStore().DefaultContainerIdentifier;
//Fetch the contacts from containers
using (var predicate = CNContact.GetPredicateForContactsInContainer(containerId))
{
CNContact[] contactList;
using (var store = new CNContactStore())
{
contactList = store.GetUnifiedContacts(predicate, keysToFetch, out
var error);
}
//Assign the contact details to our view model objects
response.AddRange(from item in contactList
where item?.EmailAddresses != null
select new ContactVm
{
PhoneNumbers =item.PhoneNumbers,
GivenName = item.GivenName,
FamilyName = item.FamilyName,
EmailId = item.EmailAddresses.Select(m => m.Value.ToString()).ToList()
});
}
BeginInvokeOnMainThread(() =>
{
tblContact.Source = new CustomContactViewController(response);
tblContact.ReloadData();
});
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
and this is my update cell method
internal void updateCell(ContactVm contact)
{
try
{
lblName.Text = contact.GivenName;
lblContact.Text = ((CNPhoneNumber)contact.PhoneNumbers[0]).StringValue;
//var no = ((CNPhoneNumber)contact.PhoneNumbers[0]).StringValue;
//NSString a = new NSString("");
// var MobNumVar = ((CNPhoneNumber)contact.PhoneNumbers[0]).ValueForKey(new NSString("digits")).ToString();
var c = (contact.PhoneNumbers[0] as CNPhoneNumber).StringValue;
}
catch(Exception ex)
{
throw ex;
}
}
I would like to know how to retrieve JUST the phone number(s) as a string value(s) i.e. "XXXXXXXXXX". Basically, how to call for the digit(s) value.
this line of code
lblContact.Text = ((CNPhoneNumber)contact.PhoneNumbers[0]).StringValue;
throw a run time exception as specified cast is not valid
Yes, exception is correct. First of all, you don't need any casts at all, contact.PhoneNumbers[0] will return you CNLabeledValue, so you just need to write it in next way
lblContact.Text = contact.PhoneNumbers[0].GetLabeledValue(CNLabelKey.Home).StringValue
//or
lblContact.Text = contact.PhoneNumbers[0].GetLabeledValue(CNLabelPhoneNumberKey.Mobile).StringValue
or you may try, but not sure if it works
contact.PhoneNumbers[0].Value.StringValue
I got solution. Here is my code if any one required.
CNLabeledValue<CNPhoneNumber> numbers =
(Contacts.CNLabeledValue<Contacts.CNPhoneNumber>)contact.PhoneNumbers[0];
CNPhoneNumber number = numbers.Value;
string str = number.StringValue;
lblContact.Text = str;
I'm trying to fetch records from a db cursor from the Client app.
Debugging Web API shows that the Cursor returns records but when returning to the Client it throws mscorlib.pdb not loaded window and clicking on Load option it throws TaskContinuation.cs not found exception
Code snippets as below ( removed irrelevant codes for readability )
WebAPI
[HttpPost("{values}")]
public async Task<ActionResult> Post([FromBody] JToken values)
{
// code removed for readility
string[] cursors = { };
cursors = await cursor.GetRpts();
CursorClass firstCursor = JsonConvert.DeserializeObject<CursorClass>(cursors[0]);
return new OkObjectResult(cursors);
}
public async Task<string[]> GetRpts()
{
try
{
DataTable[] dataTables;
CursorClass[] cursorClasses = new CursorClass[5];
//stripped some code
using (DataAccess dataAccess = new DataAccess()
{
ParamData = PrepareDoc(),
ProcedureName = Constants.Rpt,
RecordSets = this.CursorNumbers,
})
{
Int32 errorNumber = await dataAccess.RunComAsync();
dataTables = dataAccess.TableData;
};
//fetching code stripped off
string[] _cursors = Array.ConvertAll(cursorClasses, JsonConvert.SerializeObject);
return _cursors;
}
catch (Exception ex)
{
string tt = ex.Message;
}
}
public async Task<Int32> RunComAsync()
{
Int32 returnValue = 0;
try
{
//open db connection
//---------- Running the Command in asysnc mode ----------
Task<int> task = new Task<int>(oracleCommand.ExecuteNonQuery);
task.Start();
returnValue = await task;
//--------------------------------------------------------
OracleRefCursor[] refCursor = { null, null, null, null, null };
for (int _sub = 0; _sub < RecordSets; _sub++)
{
//DT declaration / connection code removed
dataAdapter.Fill(dataTable, refCursor[_sub]);
TableData[_sub] = dataTable;
}
}
catch (Exception ex)
{
return LogMsg(ex);
}
finally
{
this.Dispose(true);
}
CloseConnection();
return LogMsg(null,"Successful Operation");
}
Client
private async Task<HttpStatusCode> CallService()
{
HttpResponseMessage _response = null;
try
{
using (HttpRequestMessage requestMessage = new HttpRequestMessage()
{
Content = new System.Net.Http.StringContent(JsonRepo, System.Text.Encoding.UTF8, HeaderJson),
RequestUri = new Uri(UriString),
Method = HttpMethod.Post,
})
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Utils.TOKEN) ;
_response = await httpClient.SendAsync(requestMessage);
if (_response.IsSuccessStatusCode)
{
string httpResponse = await _response.Content.ReadAsStringAsync();
httpString = JsonConvert.DeserializeObject<string[]>(httpResponse);
}
}
}
return ErrorCode;
}
Is that something related to async operation? while debugging the API it confirms the Datatable with records . Any inputs are deeply appreciated.
error image
TIA
I have a program like the following:
main() async {
ooClass = new OoClass(1);
int val = await function1();
print(val);
ooClass = new OoClass(2);
val = await function1();
print(val);
ooClass = new OoClass(3);
val = await function1();
print(val);
}
OoClass ooClass;
Future<int> function1() async {
List list3 = await function2();
return list3.indexOf('Ok');
}
Future<List<String>> function2() async {
List<String> list1 = new List<String>();
function3(Map<String, int> map1) async {
String string1 = '';
bool bool1 = false;
List<String> list2 = [];
String string2;
function4(String string3) async {
if (ooClass.function7(string3)) return;
if (ooClass.function8() && !bool1) {
bool1 = true;
return;
}
string2 = await function5(string3);
list2.add(string2);
}
for (String key in map1.keys) {
await function4(key);
}
string1 = list2.join(', ');
list1.add(string1);
}
for (Map<String, int> idxList in ooClass.function6()) {
await function3(idxList);
}
return list1;
}
function5(String s1) {
return new Future.value('Ok');
}
class OoClass {
List<Map<String, int>> map2;
bool bool3 = false;
OoClass(int type) {
switch(type) {
case 1:
map2 = [{'Ok':1}];
break;
case 2:
map2 = [{'id': 1, 'Ok':1}];
break;
case 3:
map2 = [{'foo': 1, 'Ok':1}];
bool3 = true;
break;
}
}
List<Map<String, int>> function6() {
return map2;
}
bool function7(String string9) {
if (string9 == 'id') return true;
return false;
}
bool function8() {
return bool3;
}
}
This snippet works perfectly.
In my real environment, instead, when await function4(key); is called, function2 returns the list1 List (empty). Function4 call is executed later but the result of function2 is lost.
I don't really understand this behavior. Could it be a bug or await inside for loop is not to be used?
If await should not be used inside for loop how could I implement it in another way?
I'm using dart 1.22.0-dev.4 but I've tried also with older (and stable) versions and I had the same result.
I finally got the problem and it did not depend on await in a for loop. It was instead an error in my code.
Yes, await is permitted inside a for loop in Dart, and it will work as expected.
for (var o in objects) {
await doSomething(o);
}
And there is even await for for Streams, if that's what you're looking for:
await for (var event in eventStream) {
print("Event received: $event");
}
Your example works correctly in DartPad. It's too complex & abstract to debug but, at least superficially, it should work. You say that the snippet doesn't work in your "real environment", though. Maybe we could help if you explained what you mean by that?
Additional tip: take full advantage of static analysis, especially the await_only_futures and unawaited_futures linter rules. This can help you catch many bugs.
List.forEach → Future.forEach
If you happen to be using .forEach() on a List, this won't work:
someList.forEach((item) async {
await longFunc(item);
)}
You'll need to use:
await Future.forEach(someList, (item) async {
await longFunc(item);
});
I mistakenly thought this applied to List.forEach until finding this answer.