I'm creating a UI that uses rabbitmq to receive multiple lists of type 'StorageMessage'. I'm using a background worker to merge all the data from the lists into a datatable and I bind to the gridview in the UI. I have put the method that receives the messages below, my problem is that the UI doesn't display all the data I expect it to. I'm guessing its because the background work is busy when the message comes in. Whats the correct approach to deal with these types of situations?
public void OnMessageArrived(MessageArrivedEventArgs<object> args)
{
var topicName = args.MessagingParticipant.TopicName;
if (_logger.IsInfoEnabled)
_logger.InfoFormat("Message Received from {0}", topicName);
try
{
if (args.To == _uniqueId.ToString() || args.To.EqualsOrdinalIgnoreCase("all"))
{
lock (_lock)
{
var receivedMessage = Serialization.FromJsonString<StorageMessage>(args.MessageBody);
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync(receivedMessage);
}
}
}
}
catch (Exception exception)
{
_logger.Error("An error occurred whilst processing the received message.", exception);
}
}
The RunWorkComplete Code looks lie
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
try
{
var res = e.Result as DataTable;
_storageDataTable = ReorderTable(res, "Date", "Factor", "Aldbrough", "Holford", "Humbly Grove", "Stublach", "Holehouse Farm", "Hatfield Moor", "Hornsea", "Hill Top", "Rough", "South Hook", "Isle Of Grain", "Dragon");
UpdateDataTable();
}
catch (Exception ex)
{
}
}
And the updateDataTable code is:
private void UpdateDataTable()
{
try
{
if (InvokeRequired)
{
BeginInvoke(new MethodInvoker(() => UpdateDataTable()));
}
else
{
radGridView1.SuspendLayout();
radGridView1.GroupDescriptors.Clear();
radGridView1.DataSource = null;
radGridView1.DataSource = _storageDataTable;
radGridView1.GroupDescriptors.Add("Factor", ListSortDirection.Ascending);
// radGridView1.MasterTemplate.AutoExpandGroups = true;
radGridView1.Refresh();
radGridView1.ResumeLayout(true);
}
}
catch (Exception exception)
{
_logger.Error("Encountered an error while updating the data table.", exception);
}
}
Thanks
Elias
Related
i have a onClick method on a buttom. when this button is pressed, i get a displayalert message.
getTokenQ has a value. my question why its going inside catch block?
private async void Button_Clicked(object sender, EventArgs e)
{
try
{
var getTokenQ = await SecureStorage.GetAsync("Save_Security_Question");
if ((String.IsNullOrWhiteSpace(getTokenQ) == false))
{
}
else
{
}
}
catch (Exception ex)
{
await DisplayAlert("Message", "Some thing went wrong. Please try different method", "ok");
}
}
no you don't need to do that, you can use .Result if you don't want to execute your code asynchronously , this code is perfectly fine :
private void Button_Clicked(object sender, EventArgs e)
{
try
{
var getTokenQ = SecureStorage.GetAsync("Save_Security_Question").Result;
if ((String.IsNullOrWhiteSpace(getTokenQ) == false))
{
}
else
{
}
}
catch (Exception ex)
{
DisplayAlert("Message", "Some thing went wrong. Please try different method", "ok");
}
}
Why in catch ! Because it's a message to display only if an exception is thrown.
Currently I'm working on widows service which is receiving messages from local private MSMQ. Queue is transactional.
Receiving is done like that:
public void ReceiveAndSaveData(MessageQueue queue, MsmqDbContext context)
{
var message = new Message();
try
{
using (var tx = new MessageQueueTransaction())
{
tx.Begin();
message = queue.Receive(tx);
var bodyReader = new StreamReader(message.BodyStream);
var jsonBody = bodyReader.ReadToEnd();
var messageData = JsonConvert.DeserializeObject<QueueMessage>(jsonBody);
/*THERE IS SOME DATA PROCESSING*/
tx.Commit();
}
}
catch (JsonSerializationException e)
{
Logger.WriteError(new LogDetail("Error occured during deserializing incoming data.", e, message.Id));
}
catch (Exception e)
{
Logger.WriteError(new LogDetail("Error occured during saving data to database", e, message.Id));
}
}
In case of JsonSerializationException, I want to delete this message from current queue. Does anybody know how to solve this problem?
Use the Abort() method and also move the tx-object creation outside the try-catch block.
public void ReceiveAndSaveData(MessageQueue queue, MsmqDbContext context)
{
bool exceptionOccurred = false;
var message = new Message();
MessageQueueTransaction tx;
try
{
exceptionOccurred = false;
using (tx = new MessageQueueTransaction())
{
tx.Begin();
message = queue.Receive(tx);
var bodyReader = new StreamReader(message.BodyStream);
var jsonBody = bodyReader.ReadToEnd();
var messageData = JsonConvert.DeserializeObject<QueueMessage>(jsonBody);
/*THERE IS SOME DATA PROCESSING*/
}
}
catch (JsonSerializationException e)
{
Logger.WriteError(new LogDetail("Error occured during deserializing incoming data.", e, message.Id));
tx.Abort(); //Rolls back the pending internal transaction
exceptionOccurred = true;
}
catch (Exception e)
{
Logger.WriteError(new LogDetail("Error occured during saving data to database", e, message.Id));
exceptionOccurred = true;
}
finally
{
if(!exceptionOccurred)
tx.Commit();
}
}
Abort() MSDN
Put tx.Commit() also inside the catch block of the JsonSerializationException
First of all, I apologize for my English.
I have a method to verify my connection to SQL (TestConneccion), and I use a timer to verify it every second.
The problem is when I lose the connection, my application hangs while it tries to connect. I'm using task to avoid this, but I am new to C#.
I would really appreciate the help
public string testConeccion()
{
var archivo = "";
try
{
odb = DatabaseFactory.CreateDatabase("TESTCONECTION");
ocn = odb.CreateConnection();
if (ocn.State == ConnectionState.Closed)
{
ocn.Open();
}
ocn.Close();
archivo = "true";
}
catch (InvalidOperationException ex)
{
archivo = ex.Message;
}
catch (Exception ex)
{
archivo = ex.Message;
}
finally
{
ocn.Close();
}
return archivo;
}
private void timerMesas_Tick(object sender, EventArgs e)
{
Task<string> T1 = Task.Run<string>(() => oClasePublica.testConeccion());
if (T1.Result == "true")
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Status_32x32);
}
else
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Warning_32x32);
}
}
Make your timer tick handler async and await your task. This will run the method asynchronously and prevent the rest of your application from hanging while it runs.
private async void timerMesas_Tick(object sender, EventArgs e)
{
string T1 = await Task.Run<string>(() => oClasePublica.testConeccion());
if (T1 == "true")
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Status_32x32);
}
else
{
btnEstado.Image = new System.Drawing.Bitmap(TOUCHREST.Properties.Resources.Warning_32x32);
}
}
The ocn.Close() in the try code is not needed because the finally will do it. Also catch (InvalidOperationException ex) is not needed because catch (Exception) covers it.
You cannot do Task.Run and then immediately test the Result because the task has not yet finished! Normally you use Task.Wait(); however this will then block your main thread.
I suggest using a BackgroundWorker that continuously checks the connection and then reports it progress. This avoids the issue of changing the image on a non-UI thread.
Here are the two alternatives i tried for catching errors, they both seem to do the same thing.. but is one preferable over the other and why ?
Alt 1:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
Task t = Task.Run(() =>
{
_someObj.SomeMethod();
});
await t; //wait here, without blocking...
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
return; //<-- bypass below code on error...
}
//other code below... does not execute...
DoSomethingElse();
}
Alt 2:
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool errOccurred = false;
Task t = Task.Run(() =>
{
try
{
_someObj.SomeMethod();
}
catch (Exception ex)
{
string errMsg = ex.Message + Environment.NewLine;
errMsg += "some unhandled error occurred in SomeMethod";
Log(errMsg);
errOccurred = true;
}//end-Catch
});
await t; //wait here, without blocking...
if (errOccurred) return; //<-- bypass below code on error...
//other code below... does not execute...
DoSomethingElse();
}
Better option is to refactor part of the code into a separate method returning a bool indicating that whether to proceed or not.
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
bool success = await SomeMethodAsync();
if (!success)
{
return;
}
//other code below... does not execute...
DoSomethingElse();
}
private async Task<bool> SomeMethodAsync()
{
try
{
await Task.Run(() => _someObj.SomeMethod());
return true;
}
catch (Exception ex)
{
string errMsg = string.Format("{0} {1}some unhandled error occurred in SomeMethod",
ex.Message, Environment.NewLine);
Log(errMsg);
return false;
}
}
It's better to refactor the code than putting it all at the same place.It's better to catch the exception within your delegate if all you need to do is log it.
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
}
However If you have another method DoSomethingElse() which might be affected by the outcome of the Task.It's better to wrap try catch around await
private async void BtnClickEvent(object sender, RoutedEventArgs e)
{
try
{
await Task.Run(() =>
{
try
{
DoSomeWork();
}
catch (Exception ex)
{
log.Error(ex.Message);
}
});
DoSomethingElse();
}
catch(Exception ex)
{
}
}
As with anything it depends.
I'd say refactor the Task.Run() section into a separate async Task method, much like Sriram Sakthivel's answer, is in general a good thing. It avoids the use of a captured bool in the lambda as in version 2, and it lets you write code that expresses intent more concisely.
That said, I would carefully consider if the "catch all -> log -> ignore" pattern is what you want. In general: catch specific exceptions and handle them specifically. For all other exceptions, you might log them, but still rethrow them with "throw;" or "throw new MoreSpecificException(originalException);".
With that in mind I would suggest that if you do the catch all approach you should do the catch all as in version 1.
To keep readability high, make the code concise with clear intent, and be explicit about handling exceptions, I would write it something like this:
private async void BtnClick(object sender, RoutedEventArgs e)
{
try
{
if (await TryDoSomethingAsync())
{
DoSomeMoreStuff();
}
}
catch (Exception ex)
{
// I am sure it is fine that any and all exceptions can be logged and ignored.
Log(ex);
// And maybe even notify the user, since I mean, who monitors log files anyway?
// If something that shouldn't go wrong goes wrong, it's nice to know about it.
BlowUpInYourFace(ex);
}
}
private async Task<bool> TryDoSomethingAsync()
{
return await Task.Run<bool>(() =>
{
try
{
_myService.DoSomething();
}
catch (SomeKnownException ske)
{
// An expected exception which is fine to ignore and return unsuccessful.
Log(ske);
return false;
}
catch (SomeOtherKnownException soke)
{
// Expected exception that indicates something less trivial, but could be more precise.
throw new MyMorePreciseException(soke);
}
// Nothing went wrong, so ok.
return true;
});
}
I've been running into a Callback problems with async programming in WPF .Net 4.5.
There should be a way of doing this code in a more understandable way (I have suppressed a big part of it to make it easier to see what is going on).
I don't think there is a way to simply remove code because I need to call Dispatcher in order to manipulate WPF controls and calls like in TbSequence.Focus() and Utils.ShowMessageBox.
private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{
Controller.Busy = true;
System.Threading.Tasks.Task.Run(() =>
{
try
{
Controller.SaveItem();
}
catch (BdlDbException ex)
{
if (ex.ExceptionSubType == DbExceptionSubTypes.UniqueViolation)
{
HandleUniqueViolation(ex);
}
else
{
string errorMessage = "";
errorMessage = ex.Message;
Dispatcher.BeginInvoke(new Action(() => Utils.ShowMessageBox(t_MessageBox.Attention, errorMessage)));
}
}
Controller.Busy = false;
});
}
catch (FieldException ex)
{
if (ex.FieldName == "FirstName")
{
TbFirstName.ValidationError = true;
TbFirstName.ApplyErrorToolTip(ex.Message);
}
}
}
public void Init(UcEdit container, Employee entity = null)
{
Controller.Busy = true;
System.Threading.Tasks.Task.Run(() =>
{
try
{
Controller.Init(entity);
}
catch (BdlEntryNotFoundException ex)
{
HandleNotFoundException(ex);
}
Container.Dispatcher.BeginInvoke(new Action(() =>
{
Container.DataContext = Controller;
// Instructions order for focusing TbSequence after load should be different in case we have an existent item
// because we have to focus the control AFTER it is filled with data, in order to set the caret position correctly.
if (Controller.IsNewItem)
{
this.DataContext = Controller;
TbSequence.Focus();
Controller.Busy = false;
}
else
{
TbSequence.TextChanged += TbSequence_TextChanged;
this.DataContext = Controller;
SetButtons();
}
}));
});
}
private void HandleUniqueViolation(BdlDbException ex)
{
string errorMessage = "";
bool isSequence = false; // if true, it's name.
if (ex.Fields[1] == "Sequence")
{
errorMessage = "There is already an Employee with the sequence \"" + Controller.Item.Sequence + "\".";
isSequence = true;
}
else
{
errorMessage = "There is already an Employee named \"" + Controller.Item.FirstName +
" " + Controller.Item.LastName + "\".";
}
errorMessage += "\r\nLoad it from Database?\r\n(All the changes on this window will be lost.)";
Dispatcher.BeginInvoke(new Action(() =>
{
MessageBoxResult res = Utils.ShowMessageBox(t_MessageBox.Question, errorMessage, MessageBoxButton.YesNo);
switch (res)
{
case MessageBoxResult.Yes:
if (isSequence)
{
System.Threading.Tasks.Task.Run(() =>
{
Controller.GetEmployeeBySequence(Controller.Item.Sequence);
Init(Container, Controller.OriginalItem);
});
}
else
{
System.Threading.Tasks.Task.Run(() =>
{
Controller.GetEmployeeByName(Controller.Item.FirstName, Controller.Item.LastName);
Init(Container, Controller.OriginalItem);
});
}
break;
case MessageBoxResult.No:
break;
}
}));
}
As you can see, there is a major Callback problem here that behaves like this:
Save_Executed (UI) -> HandleUniqueViolation (Task) -> ShowMessageBox (UI) -> Controller.GetEmployeeBySequence (Task) -> Controller.Init ...
And so it goes.
Is there a way to make this code more easy to read?
Thank you.
You're starting off your code by putting (more or less) the entirety of your method body in a call to Task.Run and then explicitly marshalling to the UI thread all over the place within that callback.
Just narrow the scope of your Task.Run call so that your UI code is just outside the call to Run rather than inside both it and a call to Invoke:
private async void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{
Controller.Busy = true;
try
{
await Task.Run(() => Controller.SaveItem());
}
catch (BdlDbException ex)
{
if (ex.ExceptionSubType == DbExceptionSubTypes.UniqueViolation)
{
HandleUniqueViolation(ex);
}
else
{
string errorMessage = "";
errorMessage = ex.Message;
Utils.ShowMessageBox(t_MessageBox.Attention, errorMessage);
}
}
Controller.Busy = false;
}
catch (FieldException ex)
{
if (ex.FieldName == "FirstName")
{
TbFirstName.ValidationError = true;
TbFirstName.ApplyErrorToolTip(ex.Message);
}
}
}
Here you're running the actual long running business operation that you have in a thread pool thread, but doing all of your error handling in the UI thread.
You can do the same thing throughout your application. Rather than putting everything into a background thread and then explicitly marshaling, just only ever execute operations in a background thread that should be entirely executed in a background thread.