Asynchronous data loading and subsequent error handling - c#

I have an application that involves a database. Previously, upon opening a window, I would query the database and use this to populate aspects of my view model. This worked reasonably well, but could create noticeable pauses when the data access took longer than expected.
The natural solution, of course, is to run the database query asynchronously and then populate the view model when that query completes. This isn't too hard, but it raises some interesting questions regarding error handling.
Previously, if something went wrong with the database query (a pretty big problem, granted), I would propagate the exception through the view model constructor, ultimately making it back up to the caller that wanted to open the window. It could then display an appropriate error and not actually open the window.
Now, however, the window opens right away, then populates later as the query completes. The question, now, is at what point should I check for an error in the background task? The window is already open, so the behavior needs to be different somehow, but what is a clean way to indicate the failure to the user and allow for graceful recovery/shutdown?
For reference, here is a snippet demonstrating the basic pattern:
public ViewModel()
{
_initTask = InitAsync();
//Now where do I check on the status of the init task?
}
private async Task InitAsync()
{
//Do stuff...
}
//....
public void ShowWindow()
{
var vm = new ViewModel(); //Previously this could throw an exception that would prevent window from being shown
_windowServices.Show(vm);
}
One option I've considered is use an asynchronous factory method for constructing the ViewModel, allowing the entire thing to be constructed and initialized before attempting to display the window. This preserves the old approach of reporting errors before the window is ever opened. However, it gives up some of the UI responsiveness gained by this approach, which allows initial loading of the window to occur in parallel with the query and also allows me (in some cases) to update the UI in increments as each query completes, rather than having the UI compose itself all at once. It avoids locking up the UI thread, but it doesn't reduce the time before the user actually sees the window and can start interacting with it.

Maybe use some kind of messaging/mediator between your viewmodel and underlying service?
Semi-pseudo code using MVVMLight
public ViewModel()
{
Messenger.Default.Register<NotificationMessage<Exception>>(this, message =>
{
// Handle here
});
Task.Factory.StartNew(() => FetchData());
}
public async Task FetchData()
{
// Some magic happens here
try
{
Thread.Sleep(2000);
throw new ArgumentException();
}
catch (Exception e)
{
Messenger.Default.Send(new NotificationMessage<Exception>(this, e, "Aw snap!"));
}
}

I dealt with a similar problem here. I found it'd be best for me to raise an error event from inside the task, like this:
// ViewModel
public class TaskFailedEventArgs: EventArgs
{
public Exception Exception { get; private set; }
public bool Handled { get; set; }
public TaskFailedEventArgs(Exception ex) { this.Exception = ex; }
}
public event EventHandler<TaskFailedEventArgs> TaskFailed = delegate { };
public ViewModel()
{
this.TaskFailed += (s, e) =>
{
// handle it, e.g.: retry, report or set a property
MessageBox.Show(e.Exception.Message);
e.Handled = true;
};
_initTask = InitAsync();
//Now where do I check on the status of the init task?
}
private async Task InitAsync()
{
try
{
// do the async work
}
catch (Exception ex)
{
var args = new TaskFailedEventArgs(ex);
this.TaskFailed(this, args);
if (!args.Handled)
throw;
}
}
// application
public void ShowWindow()
{
var vm = new ViewModel(); //Previously this could throw an exception that would prevent window from being shown
_windowServices.Show(vm);
}
The window still shows up, but it should be displaying some kind of progress notifications (e.g. using IProgress<T> pattern), until the end of the operation (and the error info in case it failed).
Inside the error event handler, you may give the user an option to retry or exit the app gracefully, depending on your business logic.

Stephen Cleary has a series of posts on his blog about Async OOP. In particular, about constructors.

Related

How to avoid cross-thread operation not valid exception in Winform service bus message receiver [duplicate]

This question already has answers here:
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
(22 answers)
Closed 1 year ago.
Have developed an Azure service bus message receiver console app which is working fine console app.
Code for console app as follows:
using System.IO;
using Microsoft.ServiceBus.Messaging;
class Program
{
static void Main(string[] args)
{
const string connectionString = "Endpoint=sb://sbusnsXXXX.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=bkjk3Qo5QFoILlnay44ptlukJqncoRUaAfR+KtZp6Vo=";
const string queueName = "bewtstest1";
var queueClient = QueueClient.CreateFromConnectionString(connectionString, queueName);
try
{
queueClient.OnMessage(message => {
string body = new StreamReader(message.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
Console.WriteLine(body);
message.Complete();
});
Console.ReadLine();
}
catch (Exception ex)
{
queueClient.OnMessage(message => {
Console.WriteLine(ex.ToString());
message.Abandon();
});
Console.ReadLine();
}
}
}
Have tried to convert to a WinForms app, so I can show the service bus message as a string in a ListBox.
I have created a new Class (Azure) with the console app code, and call the method in the main form.
Class Azure:
using System.IO;
using Microsoft.ServiceBus.Messaging;
public class Azure
{
public static void GetQueue(Form1 form)
{
const string connectionString = "Endpoint=sb://sbusnsXXXX.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=bkjk3Qo5QFoILlnay44ptlukJqncoRUaAfR+KtZp6Vo=";
const string queueName = "bewtstest1";
var queueClient = QueueClient.CreateFromConnectionString(connectionString, queueName);
try
{
queueClient.OnMessage(message => {
string body = new StreamReader(message.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
//Form1 f = new Form1();
form.listBox1.Items.Add(body);
Console.WriteLine(body);
message.Complete();
});
Console.ReadLine();
}
catch (Exception ex)
{
queueClient.OnMessage(message => {
Console.WriteLine(ex.ToString());
message.Abandon();
});
Console.ReadLine();
}
}
}
Main Form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Azure.GetQueue(this);
}
}
The code compiles, however when a new service bus message is received I get the following exception:
System.InvalidOperationException: 'Cross-thread operation not valid:
Control 'listBox1' accessed from a thread other than the thread it was
created on.'
Any thoughts on how I can avoid this exception (note I have tried using InvokeRequired but can't get the code to compile)?
(Feel like I'm close as when I stop and re-run the program, the form loads with the message in the ListBox as shown here: listbox with message!)
Of course you cannot reference a Control created in the UI Thread from another thread; as you have noticed, a Invalid Cross-thread operation exception is raised when you try to: a Windows Forms app must be single-threaded, the reasons are well explained in the STAThreadAttribute Class documentation.
Note: Remove all Console.ReadLine(), you cannot use that in WinForms (there's no Console).
Here some implementations that may work for you, in order of relevance in your context (well, that's what I think, at least. You pick what you prefer).
▶ Progress<T>: this class is really simple to use. You just need to define its return type (the T type, it can be anything, a simple string, a class object etc.). You can define it in-place (where you call your threaded method(s)) and pass its reference. That's all.
The method that receives the reference calls its Report() method, passing the value(s) defined by T.
This method is executed in the Thread that created the Progress<T> object.
As you can see, you don't need to pass a Control reference to GetQueue():
Form side:
// [...]
var progress = new Progress<string>(msg => listBox1.Items.Add(msg));
Azure.GetQueue(progress);
// [...]
Azure class side:
public static void GetQueue(IProgress<string> update)
{
// [...]
try {
queueClient.OnMessage(message => {
string body = new StreamReader(message.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
update.Report(body);
message.Complete();
});
}
// [...]
}
▶ SynchronizationContext (WindowsFormsSynchronizationContext) Post(): this class is used to sync threading contexts, its Post() method dispatches an asynchronous message to the synchronization context where the class object is generated, referenced by the Current property.
Of course, see Parallel Computing - It's All About the SynchronizationContext.
The implementation is no much different than the previous: you can use a Lambda as the SendOrPostCallback delegate of the Post() method.
An Action<string> delegate is used to post to the UI Thread without the need to pass a Control reference to the Azure.GetQueue() method:
Form side:
// Add static Field for the SynchronizationContext object
static SynchronizationContext sync = null;
// Add a method that will receive the Post() using an Action delegate
private void Updater(string message) => listBox1.Items.Add(message);
// Call the method from somewhere, passing the current sync context
sync = SynchronizationContext.Current;
Azure.GetQueue(sync, Updater);
// [...]
Azure class side:
public static void GetQueue(SynchronizationContext sync, Action<string> updater)
{
// [...]
try {
queueClient.OnMessage(message => {
string body = new StreamReader(message.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
sync.Post((spcb) => { updater(body); }, null);
message.Complete();
});
}
// [...]
}
▶ Control.BeginInvoke(): you can use BeginInvoke() to execute a delegate (usually as a Lambda) asynchronously on the thread that created a Control's handle.
Of course, you have to pass a Control reference to the Azure.GetQueue() method.
That's why, in this case, this method has a lower preference (but you can use it anyway).
BeginInvoke() doesn't require to check Control.InvokeRequired: this method can be called from any thread, including the UI Thread. Calling Invoke() instead requires that check, since it could cause a dead-lock if used from the UI Thread
Form side:
Azure.GetQueue(this, Updater);
// [...]
// Add a method that will act as the Action delegate
private void Updater(string message) => listBox1.Items.Add(message);
Azure class side:
public static void GetQueue(Control control, Action<string> action)
{
// [...]
try {
queueClient.OnMessage(message => {
string body = new StreamReader(message.GetBody<Stream>(), Encoding.UTF8).ReadToEnd();
control.BeginInvoke(new Action(()=> action(body));
message.Complete();
});
}
// [...]
}
You can also use System.Windows.Threading.Dispatcher to manage a Thread's queued work items, calling its BeginInvoke() (preferable) or Invoke() methods.
Its implementation is similar to the SynchronizationContext one and its methods are called as the Control.BeginInvoke() method already mentioned.
I'm not implementing it here, since the Dispatcher requires a reference to WindowsBase.dll (WPF, usually) and this can cause undesired effects in a WinForms application that is not DpiAware.
You can read about this here:
DPI Awareness - Unaware in one Release, System Aware in the Other
Anyway, in case you're interested, let me know.

Load data (async/await)

I'm not sure about this state. I need to get data from database asynchrony.
I have class DB
public class Db{
public async Task<ObservableCollection<Person>> GetAllPerson()
{
using (var context = new Db())
{
// get data and return ObservableCollection<Person>
}
}
}
In the ViewModel I call LoadData function.
public class VM{
public ObservableCollection<Person> Person { get; set; }
private readonly DB sqlRepository;
public VM()
{
sqlRepository=new DB();
LoadData();
}
private async void LoadData()
{
Person= await sqlRepository.GetAllPerson();
}
}
I got warning: Warning CS1998 This async method lacks 'await' operators and will run synchronously.
How can I run my function asynchronously?
Should I use ?
Person=await Task.Run(()=>this.sqlRepository.GetAllPerson());
How can I run my function asynchronously?
You're approaching your problem from the wrong direction. You're trying to go "outside in" - your ViewModel wants to load the database data asynchronously. And that's a fine way of describing the problem, but it's the wrong way to solve it.
To solve it more easily, start at the other end. Whatever methods are actually calling into the database (e.g., Entity Framework calls) should be made asynchronous first, and then let async grow out from there. Eventually you'll end up with something like:
public async Task<ObservableCollection<Person>> GetAllPersonAsync()
{
using (var context = new Db())
{
// This code wasn't shown in the question.
// But from the compiler warning, it was probably using something like
// var people = People.ToList();
// return new ObservableCollection<Person>(people);
// And the async version should be:
var people = await People.ToListAsync();
return new ObservableCollection<Person>(people);
}
}
Which you could consume as:
private async void LoadData()
{
Person = await sqlRepository.GetAllPersonAsync();
}
But I recommend consuming it via NotifyTask as described in my MVVM async data binding article. That approach would give you the ability to data-bind busy spinners and whatnot.
Should I use [Task.Run]?
No. That's "fake asynchrony" - where your code acts like it's asynchronous but it's really just synchronously running on a background thread.

Async method that throws exception won't resume the thread context back to the same thread

When I am using async await and an exception is thrown the thread context is being lost. In my code I'm using dependency injection that registered to resolve per thread so I need to execute my code on the same thread.
This is how it is setup:
I have a method that will try calling different communicators using async when one throws an exception it will go onto the next one:
public async Task<TResponse> VisitRequestAsync(Context context)
{
/* ....
prepare request from context
.... */
var communicatorEnumerableInstance = _communicatorService.GetCommunicatorInstanceEnumerable();
foreach (var communicator in communicatorEnumerableInstance)
{
using (communicator)
{
var communicatorInstance = communicator as ICommunicator<TResponse, TRequest>;
try
{
return await communicatorInstance.ProcessAsync(request).ConfigureAwait(true);
break;// call will break out of the for-each loop if successful processed.
}
catch (Exception exception)
{
continue;// Continue to load next communication method/instance
}
}
}
}
Below is a unit test that contains a communicator that always throws an exception and one that tries to get a dependency that is registered onto the original thread.
public class TestDependancy : ITestDependancy
{
}
public interface ITestDependancy
{ }
public class TestCommunicatorThrowsException :
ICommunicator<ResponseType, RequestType>
{
public async Task<ResponseType> ProcessAsync(RequestType request)
{
var task = Task.Run(() =>
{
throw new Exception();
return new ResponseType();
});
return await task;
}
public void Dispose()
{
}
}
public class TestCommunicatorGetsDependency :
ICommunicator<ResponseType, RequestType>
{
public TestCommunicatorGetsDependency()
{ }
public async Task<ResponseType> ProcessAsync(RequestType request)
{
TestDependancy = DefaultFactory.Default.Resolve<ITestDependancy>();
var task = Task.Run(() => new ResponseType());
return await task;
}
public ITestDependancy TestDependancy { get; set; }
public void Dispose()
{
}
}
[TestMethod]
[TestCategory("Unit")]
public async Task it_should_be_able_to_resolve_interface_from_original_thread()
{
var secondCommunicator = new TestCommunicatorGetsDependency();
_communicators = new ICommunicator<ResponseType, RequestType>[]
{new TestCommunicatorThrowsException(), secondCommunicator};
_communicatorServiceMock.Setup(
x => x.GetCommunicatorInstanceEnumerable(It.IsAny<string>(), It.IsAny<string>()))
.Returns(_communicators);
((IFactoryRegistrar) DefaultFactory.Default).RegisterPerThread<ITestDependancy, TestDependancy>();
var firstInstance = DefaultFactory.Default.Resolve<ITestDependancy>();
await it.VisitRequestAsync(_context).ConfigureAwait(true);
var secondInstance = secondCommunicator.TestDependancy;
Assert.AreEqual(firstInstance, secondInstance);
}
When the dependencies are resolved in the unit test they are not equal. After looking into it I see that the value for CurrentThread.ManagedThreadId changes at the point when the exception gets thrown. Then when it is caught in the VistRequestAsync method the CurrentThread.ManagedThreadId is never restored to its original state. So then the dependency injection is unable to get the same instance because it is now operating on a different thread.
Originally, I was using .ConfigureAwait(false) with the await. Then I tried setting it to true and I started seeing it sometimes get the same thread back. Which sounds a lot like what is said in this answer.
This post about the synchronization context and async sounds a lot like the problem I am facing. My trouble is I'm using WebApi and need a response back when things get done so I'm not sure how to use his message pump and asynchronously wait for an answer.
Async uses the ThreadPool to process tasks. This means that there is no guarantee that an async operation will start and complete on the same thread.
When a async task is first awaited, the task is put on a work queue. As soon as possible, the task scheduler grabs that task from the queue and assigns it to one of the many available threads.
For more information, see this overview of the structure of the TPL: https://msdn.microsoft.com/en-us/library/dd460717(v=vs.110).aspx.
If you need a context that flows with the thread, look at using something like the logical call context or CallContext.LogicalSetData / LogicalGetData.
But the behavior you're seeing is correct, and as mentioned has nothing to do with whether or not an exception is thrown. You'll see different thread ids at various points of an asynchronous task's scheduling, execution, and completion.

Marshalling data back to UI Thread from within Async Action

I've got an ICommand that needs to set data to a property on the UI Thread.
public override async void Execute(object parameter)
{
var vm = (MyVm)parameter;
var data = await _myDataService.GetData();
vm.MyData = data; // must be set on UI Thread due to binding.
}
Now I want to wrap my call in an event logger (I originally wanted to do AOP and decorate the method with a logging attribute, but I couldn't figure it out in a PCL). So I moved onto wrapping my call like this.
public override void Execute(object parameter)
{
EventLogger.LogEvent(this,
EventLogEntryType.Command,
EventLogErrorSeverity.Warning,
Errors.GetServiceAreaCommand_ErrorMessage,
async () =>
{
var vm = (MyVm)parameter;
var data = await _myDataService.GetData();
vm.MyData = data; // must be set on UI Thread due to binding.
});
}
Here's the LogEvent method.
public static void LogEvent(object sender,
EventLogEntryType entryType,
EventLogErrorSeverity eventLogErrorSeverity,
string friendlyErrorMessage,
Action action)
{
var name = sender.GetType().Name.SplitCamelCase();
var startEntry = new EventLogEntry(entryType);
LogEvent(string.Format("Start: {0}", name), startEntry);
try
{
action.Invoke();
}
catch (Exception ex)
{
var exEntry = new EventLogEntry(EventLogEntryType.Error, friendlyErrorMessage, false, ex)
{
ErrorSeverity = eventLogErrorSeverity
};
LogEvent(string.Format("Error: {0}", name), exEntry);
if (eventLogErrorSeverity == EventLogErrorSeverity.Critical)
{
throw;
}
}
var endEntry = new EventLogEntry(entryType);
LogEvent(string.Format("Finish: {0}", name), endEntry);
}
The problem is that it appears as though I'm STILL setting the property on a background thread instead of the Main thread (IllegalStateException in Android).
What is the cleanest way to set the data as is being done in the first example, while still wrapping the Action in a logging method?
I also had success creating a base class for ICommand, but it A) changed the method signatures for CanExecute and Execute, and B) it also (obviously) doesn't extend it's capabilities beyond Commands.
I'm looking for a clean way to log methods (BeforeExecute, AfterExecute, OnError) no matter what they do.
As an aside, the ideal logging mechanism would be to use an Interceptor, but I'm just not strong enough in my C# chops to implement it.
[Log(EventLogEntryType.Command, EventLogErrorSeverity.Warning, "Some Friendly Message")]
public override async void Execute(object parameter)
{
var vm = (MyVm)parameter;
var data = await _myDataService.GetData();
vm.MyData = data; // must be set on UI Thread due to binding.
}
If you have (caveat below) access to the Activity object in your code then you can probably do;
Activity.RunOnUiThread(() => {
//Execute my code on UIThread here
});
But it's an if, because I note you're using a PCL, or have referenced using one, so I suspect that a shared library is not going to know anything about the Activity (unless you pass that too). Very much depends on your app structure and where this code is, but within the main Xamarin.Android project where your views are the above should work

How to ensure that a system level operation is atomic? any pattern?

I have a method which internally performs different sub-operations in an order and at failure of any of the sub operation i want to Rollback the entire operation.
My issue is the sub-operations are not all database operations. These are mainly system level changes like adding something in windows registry, creating a folder at a specified path and setting permissions etc. the sub-operations can be more than this.
want to do somthing like this;
CreateUser(){
CreateUserFtpAccount();
CreateUserFolder();
SetUserPermission();
CreateVirtualDirectoryForUser();
....
....
....
and many more
}
if last operation fails, i want to roll back all previous operations.
So, what is the standard way to do this? is there a design pattern do handle this?
Note: i'm using C#.net
Here's one way to do it:
Using the command pattern, you can create undoable actions. With each operation, you register the related commands, so that you can undo the executed commands when a fail condition occurs.
For example, this might all belong in a transaction-like context object that implements IDisposable and put in a using block. The undoable actions would be registered to this context object. On dispose, if not committed, "undo" is carried out for all registered commands. Hope it helps. The downside is you may have to convert some methods to classes. This might be a necessary evil though.
Code sample:
using(var txn = new MyTransaction()) {
txn.RegisterCommand(new CreateUserFtpAccountCommand());
txn.RegisterCommand(new CreateUserFolderCommand());
txn.RegisterCommand(new SetUserPermissionCommand());
txn.RegisterCommand(new CreateVirtualDirectoryForUserCommand());
txn.Commit();
}
class MyTransaction : IDisposable {
public void RegisterCommand(Command command){ /**/ }
public void Commit(){ /* Runs all registered commands */ }
public void Dispose(){ /* Executes undo for all registered commands */ }
}
class UndoableCommand {
public Command(Action action) { /**/ }
public void Execute() { /**/ }
public void Undo{ /**/ }
}
Update:
You mentioned that you have hundreds of such reversible operations. In this case, you can take a more functional approach and get rid of UndoableCommand completely. You would register delegates instead, like this:
using(var txn = new MyTransaction()) {
txn.Register(() => ftpManager.CreateUserAccount(user),
() => ftpManager.DeleteUserAccount(user));
txn.Register(() => ftpManager.CreateUserFolder(user, folder),
() => ftpManager.DeleteUserFolder(user, folder));
/* ... */
txn.Commit();
}
class MyTransaction : IDisposable {
public void Register(Action operation, Action undoOperation){ /**/ }
public void Commit(){ /* Runs all registered operations */ }
public void Dispose(){ /* Executes undo for all registered and attempted operations */ }
}
As a note, you'd need to be careful with closures with this approach.
I think your best bet would be to encapsulate the execution and reversal of each step of the process. It will make a lot more easily read code than nested try-catch blocks. Something like:
public interface IReversableStep
{
void DoWork();
void ReverseWork();
}
public void DoEverything()
{
var steps = new List<IReversableStep>()
{
new CreateUserFTPAccount(),
new CreateUserFolder(),
...
}
var completed = new List<IReversableStep>();
try
{
foreach (var step in steps)
{
step.DoWork();
completed.Add(step);
}
}
catch (Exception)
{
//if it is necessary to undo the most recent actions first,
//just reverse the list:
completed.Reverse();
completed.ForEach(x => x.ReverseWork());
}
}
Both NTFS and the Registry support enrollment in KTM and MS DTC transactions (and by extension, TransactionScope). However, the transactional file system has been deprecated due to complexity, and may not be in some future version of windows.
Example of using transactional file system and registry from C#
Transactional NTFS
If not everything fits in a transaction, I would certainly look to the command history patterns presented in other answers to this question.
I'm not aware of any standard pattern for this type of thing but I'd probably do it with nested try/catch blocks myself - with appropriate code for the rollback of non-database operations in the catch block. Use a TransactionScope to ensure all the database operations are transactionactional.
eg:
using (TransactionScope scope)
{
try
{
DoOperationOne();
try
{
DoOperationTwo();
DoDataBaseOperationOne(); // no need for try/catch surrounding as using transactionscope
try
{
DoOperationThree();
}
catch
{
RollBackOperationThree();
throw;
}
}
catch
{
RollBackOperationTwo();
throw;
}
}
catch
{
RollbackOperationOne();
throw;
}
scope.Complete(); // the last thing that happens, and only if there are no errors!
}

Categories

Resources