Need to wrap your head around asynchronous operations

I have a custom control, and I have the interface that this control provides to the user.

public interface ILookupDataProvider { string IdColumnName { get; } IEnumerable<IDataColumn> Metadata { get; set; } void GetDataAsync(string parameters, Action<IEnumerable<object>> onSuccess, Action<Exception> onError); } 

So this is my attempt to expose the async operation in GetDataAsync

But I don’t know how to implement this method in my class that implements the interface. I understand this part, since I have a method that will be executed, and then onCompletion , onSucess or onError delegate is called.

Can someone help with the syntax on how to write them?

EDIT:

This is 4.0 and I cannot use await commands

EDIT 2:

I use the DevForce framework to load data, but for the sake of this example - let, for example, the WCF service work. How can I wrap a WCF service call in my interface implementation?

Also, what do you think is normal to create such an interface to represent an async operation? Would you do it differently with an event, for example?

+4
source share
3 answers

The main idea here is that there will be a background thread in the request. After the operation completes, you will use the onSuccess and onError to report new values. for instance

 void GetDataAsync( string parameters, Action<IEnumerable<object>> onSuccess, Action<Exception> onError) { WaitCallback doWork = delegate { try { IEnumerable<object> enumerable = GetTheData(parameters); onSuccess(enumerable); } catch (Exception ex) { onError(ex); } }; ThreadPool.QueueUserWorkItem(doWork, null); } 
+6
source

You really do not want to use this template:

 void GetDataAsync(string parameters, Action<IEnumerable<object>> onSuccess, Action<Exception> onError); 

Instead, you want to use this:

 Task GetDataAsync(string parameters); 

When you return Task you return an instance representing the asynchronous unit of work. From there, the consumer of the API can choose ContinueWith and decide what to do when it succeeds, or if there is an error.

However, there is a design flaw in your example. In a method called GetDataAsync I expect the data to be returned. This is not a problem, you can simply change the signature to:

 Task<MyData> GetDataAsync(string parameters); 

Now this returns a Task<T> , which you can use the Result property to get the result (it will be blocked if the task fails), or you can use the ContinueWith method again to process the data when the async operation is performed.

Alternatively, you can take an instance of the CancellationToken parameter to determine if you should cancel your operation:

 Task<MyData> GetDataAsync(string parameters, CancellationToken cancellationToken); 

Again, ContinueWith will allow you to specify an action to cancel.

Note that this is how the methods using await and async in Async CTP are modeled; they return Task or Task<T> ; doing the same in your code will allow you to be prepared when these language functions are baked.

+3
source

To use tasks, you can use them like this. The only difficult task is to make a callback in the user interface thread, which is achieved using TaskScheduler.FromCurrentSynchronizationContext (), so you can update your interface or display a message if something went wrong.

Due to the nature of the events associated with the event, it may happen that if you clog a button that launches WCF calls, you do not get the results back in the order in which you sent the requests. This can be prevented by saving the running task and canceling the last running task if you want to start a new operation, or you can simply ignore subsequent requests during the execution of the task.

 private void button1_Click(object sender, EventArgs e) { GetDataAsync("www.data.com").ContinueWith(result => { if (result.Exception != null) { MessageBox.Show(this, "Error: {0}" + result.Exception, "Error"); } else { foreach (var obj in result.Result) { textBox1.Text += obj.ToString(); } } }, TaskScheduler.FromCurrentSynchronizationContext() ); } Task<IEnumerable<object>> GetDataAsync(string parameters) { return Task<IEnumerable<object>>.Factory.StartNew(() => { Thread.Sleep(500); // throw new ArgumentException("uups"); // make wcf call here return new object[] { "First", "second" }; }); } 
+1
source

Source: https://habr.com/ru/post/1380064/


All Articles