Create a simple asynchronous call mode for a Windows application (with instance code)

Source: Internet
Author: User
Source: msdn

Abstract: In a blogArticleDavid Hill introduced how to asynchronously call Web Services in Windows applications. This method can solve the thread freezing problem.

Code: asyncserviceagent.rar

Note: This article is from you can also say that Microsoft does not have the copyright to the information in this article, and it is not guaranteed. This article only represents the author's point of view, rather than Microsoft's strategy, ideas, or standard practices. AllCodeThere is no direct or indirect warranty, including for commercial or other purposes. To facilitate reading and unify the format of Microsoft articles, the original blog articles were adjusted reasonably.


Recently I have compiled many smart client applications and summarized some applicationProgramWhen the Web Service is called in the background, the asynchronous call method on the foreground interface is not frozen. Although the. NET Framework itself already provides an asynchronous call mechanism, I find it difficult to grasp this mechanism in Windows applications, because you need to properly control the user interface thread processing.

In this article, I will teach you a simple method for Asynchronously calling Web Services in Windows applications, you no longer need to consider the interaction between background threads and foreground interface threads.

Service Proxy

Visual Studio. net will generate a good web service proxy class, through which web services can be used asynchronously, but this proxy class implements. net Framework, as described above, this mechanism is not very convenient for Windows applications. For this reason, I generally do not directly use the generated proxy class, but add a Service proxy class in the middle.

A Service proxy class is a class with additional functions that can help clients interact with Web Services. The Service proxy class provides many useful functions, including data caching, secure identity management, and offline operation support. The Service proxy created in this article is analogous to the normal proxy class of the. NET Framework itself to implement a simpler asynchronous call mode.

User Interface thread

An application starts from a thread that creates and manages the user interface. This thread is called a user interface thread. Most developers instinctively use User Interface threads to complete all the work, including Web service calls, remote object calls, and database access, most usage and performance problems are caused by this inappropriate method.

The essence of the problem is that you can never accurately predict the time required to access web services, remote objects, or databases. In addition, when you call this type in the user interface thread, the user interface may have an annoying freeze.

Naturally, you will place this type of calls in a separate thread, but I have taken another step, we recommend that you create all non-user interface workshops in a separate thread. In my opinion, the user interface thread is only used to manage the user interface, and all the object calls that you cannot guarantee a good response time should be asynchronous, whether in-process, cross-process or cross-computer.

In any case, try to simplify the asynchronous call mode of user interface thread processing. I have implemented a simple asynchronous call mode similar to a feature in Visual Studio 2005. First, let's explain how the asynchronous call mode works in the current. NET Framework.

. Net asynchronous call mode

Each Web function of the Web Service proxy class generated by the system has a begin and an end method. Each object that supports the. NET Framework asynchronous call mode is similar to this. When an asynchronous call is started, the client immediately responds when calling the begin method, or immediately responds after an independent thread accessing the Web service is established. At a later time, after the Web service access is completed, the client calls the end method.

But how does the client know when to call the end method? The begin method returns an iasyncresult object, which can help you track the asynchronous call process and explicitly wait for the background thread to complete. However, if you do this in the user interface thread, will reduce the synchronization of the entire system. A better way is to register a callback function in the user interface process and generate an automatic notification when other work is completed.

Let's take a look at the sample code. In this code, we get some customer data from a Web Service. These functions are completed through the getmermerdata method in the Web Service proxy class. We can start this web service call and use the following code to register a callback function to generate a function to interact with the application in the user interface thread.

Private void someuievent (Object sender, eventargs e) {// create a callback delegate so we will/be notified when the call has completed. asynccallback callback = newasynccallback (customerdatacallback); // start retrieving the customer data. _ proxy. begingetcustomerdata ("Joe Bloggs", callback, null );}

The customerdatacallback method is returned for a Web service call. In this method, we need to call the end method in the Web Service proxy class that is actually used to obtain customer data. This method can be implemented as follows:

Public void customerdatacallback (iasyncresult AR) {// retrieve the customer data. _ customerdata = _ proxy. endgetcustomerdata (AR );}

Now, you must note that this method is called by the background worker thread. If you want to use the information you just obtained on the front-end interface (for example, display the customer data in a data grid control), do not forget to update it in the user interface thread. If you forget to do so, there will be a lot of inexplicable errors, and debugging is quite difficult.

So how can we switch the thread? We can use the service proxy method. All controls are implemented from these objects. We can implement a method called from the user interface thread, in which we can safely update our interface. To use the control. Invoke method, we must pass a delegate to the user's update method. Now, the code of the customerdatacallback method is updated as follows:

Public void customerdatacallback (iasyncresult AR) {// retrieve the customer data. _ customerdata = _ proxy. endgetcustomerdata (AR); // create an eventhandler delegate. eventhandler updateui = new eventhandler (updateui); // invoke the delegate on the UI thread. this. invoke (updateui, new object [] {null, null });}

The updateui method can be implemented as follows:

Private void updateui (Object sender, eventargs e) {// update the user interface. _ DataGrid. datasource = _ customerdata ;}

This is not very rigorous and scientific, so it can simplify the complex problem of "Two jumps. The key is that the original call of the Asynchronous Method (taking the winform class as an example) is used to handle the conversion thread, and another delegate and control. Invoke method are required.

A simplified asynchronous call mode

I often use a technology to reduce the complexity and amount of code used to create asynchronous calls, that is, to put thread switching and delegate implementation into an intermediate class. This makes it unnecessary for us to consider the thread and delegation issues when performing asynchronous calls from the user interface class. I call this technology automatic callback. With this technology, the above example can be improved as follows:

Private void someuievent (Object sender, eventargs e) {// start retrieving the customer data. _ serviceagent. begingetcustomerdata ("Joe Bloggs ");}

After the Web Service is accessed, the following methods are automatically called:

Private void getcustomerdatacompleted (Dataset customerdata) {// This method will be called on the UI thread. // update the user interface. _ DataGrid. datasource = customerdata ;}

The name of the callback function is determined by the name of the original asynchronous call (so you do not need to create or pass the delegate), and the callback function can be called by the correct thread (control is no longer required. ). These methods are simple and error-prone.

There is no free lunch in the world. We need to write the Magic Code to implement this simple model. The Code listed below is written into the serviceagent class:

Public class serviceagent: autocallbackserviceagent {private customerwebservice _ proxy; // declare a delegate to describe the autocallback // method signature. private delegate voidgetcustomerdatacompletedcallback (Dataset customerdata); Public serviceagent (Object callbacktarget): Base (callbacktarget) {// create the Web Service proxy object. _ proxy = new customerwebservice ();} public void begingetcustomerdata (string customerid) {_ proxy. begingetcustomerdata (customerid, new asynccallback (getcustomerscallback), null);} private void getcustomerdatacallback (iasyncresult AR) {dataset customerdata = _ proxy. endgetcustomerdata (AR); invokeautocallback ("getcustomerdatacompleted", new object [] {customerdata}, typeof (getcustomerscompletedcallback ));}}

In this example, the Service proxy class code is simple and easy to reuse. All we need to do is compile a similar set of common code for the winform class. We have effectively increased the importance of thread management, and separated it from the preparation of the background asynchronous call of object code and the preparation of foreground client code.

The autocallbackserviceagent base class is a simple class that implements the invokeautocallback method. The Code is as follows:

Public class autocallbackserviceagent {private object _ callbacktarget; Public autocallbackserviceagent (Object callbacktarget) {// store reference to the callback target object. _ callbacktarget = callbacktarget;} protected void invokeautocallback (string methodname, object [] parameters, type delegatetype) {// create a delegate of the correct type. delegate autocallback = delegate. createdelegate (delegatet Ype, _ callbacktarget, methodname); // if the target is a control, make sure we // invoke it on the correct thread. control targetctrl = _ callbacktarget assystem. windows. forms. control; If (targetctrl! = NULL & targetctrl. invokerequired) {// invoke the method from the UI thread.tar getctrl. invoke (autocallback, parameters);} else {// invoke the method from this thread. autocallback. dynamicinvoke (parameters );}}}

The code above creates a callback function delegate and determines whether the callback function is called in the call thread or in the user interface thread. If the call target is a control object, it will call the callback function from the user interface thread as needed.

Explore these interesting details. if you carefully check the code, you will find that we can simplify it by specifying automatic callback delegation in the base class. If we do not need to sign the callback delegate, We can automate almost all things and simplify the basic service proxy class to implement only one line of code in the begingetcustomerdata method.

Why do we need to specify this delegate? That's because we also need to use the control. Invoke method. Unfortunately, the developer of. NET Framework does not provide a methodinfo object for this method, but it can make writing Basic code much easier.

An alternative is to specify a standard delegate type and use it for all callback function signatures. For example, we can require all automatic callback functions to use a method signature. This method signature is used to maintain the original object group and return the Web service parameters to the client. The delegate declaration method is as follows:

Public Delegate void autocallback (object [] parameters );

Using this delegate can greatly simplify the code of the Service proxy class, but the returned data must be converted to a certain format in the client code.

Is this worthwhile?

Is it necessary to implement a Service proxy class as above? It depends on how much you want to simplify the work of user interface developers. Writing a Service proxy class above may not necessarily reduce the amount of code, but it can make the division of labor between interface developers and background service developers clearer and more effective.

In addition to providing this simple asynchronous call mode, we can also add more useful functions to the Service proxy class. In the future, I will continue to expand on the basis of this idea to show you how to implement advanced functions such as automatic local data caching in the Service proxy class. Implementing these advanced functions in the Service proxy class means that the user interface developers can complete their work more easily.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.