Replacing the user interface when implementing custom asynchronous WCF call processing using tasks and callbacks in a WPF application

I have an MVVM WPF application. The View model has several properties associated with the view, and these properties are populated with data coming from the database directly or through the wcf service, which is located between the view model and the database. The choice of data connection mode depends on the application settings in the App.config file of the client application. I want to implement my own way of calling service methods asynchronously and processing return values. I would like to know if there is a possibility of problems with threads if I implement it as follows with the Task:

Service call flow: ViewModel> ServiceAgent> (MyWCFServiceClient or MyBusinessClient)> MyBusinessClass> Inorder database for using service operations I have a MyWCFServiceClient class that implements IMyWCFService (generated when adding a service link).

In addition, I have a class MyBusinessClassClient, which is implemented from the same IMyWCFService interface. Thus, both MyWCFService and MyBusinessClient have the same method signatures. I decided not to generate any asynchronous methods when creating the service client, because if so, I might need to implement so many unnecessary materials created by IMyWCFService in MyBusinessClient.

Suppose I have a GetEmployee (int id) method that returns an Employee object defined in IMyWCFService. Thus, both classes MyWCFServiceClient and MyBusinessClient will have their own implementations.

In my ViewModel, I have:

private void btnGetEmployee_Click() { ServiceAgent sa = new ServiceAgent (); //this call/callback process the service call result sa.GetEmployee(1673, (IAsyncResult ar) => { Task<Employee> t1 = (Task<Employee>)ar; Employee = t1.Result; //do some other operation using the result //do some UI updation also }); } //this property is bound a label in the view private Employee _employee; public Employee Employee { get { return _ employee; } set { _ employee = value; OnPropertyChanged(() => Employee); } } 

The ServiceAgent class is implemented as follows:

 public class ServiceAgent { private IMyWcfService client; public ProxyAgent() { //The call can go to either MyWCFServiceClient or //MyBusinessClient depending on this setting //client = new MyBusinessClient(); //OR client = new MyWcfServiceClient(); } public void GetEmployee(int id, AsyncCallback callback) { //My implementation to execute the service calls asynchronously using tasks //I don't want to use the complex async mechanism generated by wcf service reference ;) Task<Employee> t = new Task<Employee>(()=>client.GetEmployee(id)); t.Start(); try { t.Wait(); } catch (AggregateException ex) { throw ex.Flatten(); } t.ContinueWith(task=>callback(t)); } } 

This is freezing my user interface. I want to avoid this. I also wonder if this is the right way for what I want to achieve. I have less experience with tasks / threads and callbacks, so Id would like to know if I will have any problems in the future (thread / memory management, etc.).

+7
source share
1 answer

@ Anant heh, I deleted the comment because, at a second glance, I thought I was reading the code incorrectly. Generally speaking, when connecting to a web service, you should always treat the call as asynchronous, because you can deal with excessive lag that blocks any thread (usually a GUI thread). This is compounded if you need to make multiple WCF calls for a single GUI action. It also gets worse, because your WCF interface is written as an asynchronous call, and then it lies and works synchronously anyway. A definite reason for future confusion.

Therefore, I believe that it is best to deal with an asynchronous model, but at least you can do type checking / casting / return processing in your WCF call. I did something similar, but instead of using synchronous calls, I will still use callbacks, but I will have an IAsyncResult handler in the WCF call, which will then pass it to the expected type and return it to the user.

 public void GetEmployee(int id, Action<Employee> getEmployeeCompletedHandler) { Task<Employee> t = new Task<Employee>(()=>client.GetEmployee(id)); t.Start(); t.ContinueWith(task=> { if (getEmployeeCompletedHandler != null) getEmployeeCompletedHandler(t1.Result); }); } 

What makes your typical use:

 sa.GetEmployee(1673, result => this.Employee = result); 

If you really want to maintain a synchronous model, you can move the work to a background thread (but it will still be โ€œasynchronousโ€ in terms of GUI). At this point, you can also use your GetEmployee method synchronously and return a value. Thus, it is obvious to the API consumer that there is no asynchronous operation:

 public Employee GetEmployee(int id) { Task<Employee> t = new Task<Employee>(()=>client.GetEmployee(id)); t.Start(); try { t.Wait(); } catch (AggregateException ex) { throw ex.Flatten(); } return t.Result; } 

Then your calling code might look like this:

 //spawn a background thread to prevent the GUI from freezing BackgroundThread.Spawn(() => { this.Employee = sa.GetEmployee(1673); }); 

Note. BackgroundThread is a custom class that you can create to create or spawn a background thread. I will leave this implementation detail for you, but I believe that it is best to have a managed wrapper for stream processing, because it makes using a lot easier and an abstract of the implementation details (using a stream stream? New stream? BackgroundWorker? Who cares!)

Just notice, I have not tried using WCF calls synchronously, which I just posted above (I stick with a complete asynchronous model like my first code example), so I think this will work. (I still do not recommend doing it this way!)

+3
source

All Articles