Calling Web Services Asynchronously

本文介绍如何使用.NET Framework进行Web服务的异步调用,避免长时间运行操作导致用户界面冻结。通过创建简单的Web服务及客户端应用程序演示了同步与异步调用的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Creating and calling Web Service methods in the .NET Framework works pretty easily. This tutorial makes a couple of assumptions:

  • You are familiar with the basic way of accessing Web Services with .NET (if you're interested in learning more about that, check the Creating and Using a Simple Web Service, Part I tutorial).
  • You are using the release version of Visual Studio .NET 7.0 (although everything but the project manipulation will work with just the .NET Framework SDK).

Sometimes, Web Services may be implemented that need an extended period of time to run. And, you don't want your Windows Form application frozen for that entire time while the operation is being carried out. Fortunately, .NET exposes mechanism for calling Web Service methods asynchronously, so that your Windows application's user interface thread is free to do other things. To do this, Web Services define a callback model that allows the client to be notified when the operation has completed. The .NET Framework implements this elegantly, so that the Web Service itself doesn't need to know or do anything to provide this type of functionality.

Web Service Code
First, let's start with a simple Web Service.
  • Create a new project and workspace by clicking on File -> New Project.
  • This will open another dialog box that allows you to select the project name, where it will be stored on disk, and what type of project it will be.
  • Fill in the information you want (you should probably leave the location as "http://localhost/" that's the setting in this tutorial)
  • Then select the project as an ASP.NET Web Service project, and click the OK button.

Now, that you have the Web Service project, here's the code for the service itself that should go into the Service1.asmx.cs file:

  
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.Threading;

namespace AsyncWebService
{
    public class Service1 : System.Web.Services.WebService
    {
        //... removed the auto-generated code ...

        [WebMethod]
        public string LongOperation(int sleepLength)
        {
            // simulate an operation that takes a long time...
            Thread.Sleep(sleepLength);
            return "This WS operation ran for " + sleepLength.ToString() + " milliseconds";
        }
    }
}

As you can see, the Web Service method itself, LongOperation, is pretty simple. It simulates a long operation by sleeping for the period of time specified by the caller. And, then returns a simple string. Nothing really different from any other Web Service method that you may have developed.

The Windows Form Client
Now, let's create a simple Windows Form to consume the Web Service. To do this:
  • Add another new project by clicking on the menu File -> New Project.
  • This time select C# Windows Application
  • Click the OK button to add the new project to the existing solution.
This will produce a project with a single form. This is the one we'll use for the tutorial.
You will also need to add a Web Reference in this project to the Web Service that we just created. To do this:
  • Select the client app in the Solution Explorer, right-click on it, and select "Add Web Reference".
  • That puts up a dialog for finding Web Services. In the Address field, just put the full path to your Web Service (in our case it's http://localhost/AsyncWebService/Service1.asmx).
  • The "Add Reference" button should now be enabled, so click on it. That will add the Web Reference to your new project.

The UI is simple. From the toolbox, drag on a label control (for outputting some text), 2 buttons, 1 status bar control (to update as service is called), and a timer control.

WinForm Client Code
Here is the client code for accessing the Web Service.

  
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace AsyncWSClient
{
    public class Form1 : System.Windows.Forms.Form
    {
        int        seconds = 0;

        // this is WinForm with a button that runs the web service sync or async methods.
        private System.Windows.Forms.Label labelDisplay;
        private System.Windows.Forms.Button buttonSync;
        private System.Windows.Forms.Button buttonAsynch;
        private System.Windows.Forms.StatusBar statusBar1;
        private System.Windows.Forms.Timer timer1;

        // ... removed auto-generated code ...

        private void buttonSync_Click(object sender, System.EventArgs e)
        {
            // runs the web service synchronously.  just a simple web service call.
            statusBar1.Text = "Running the query...";
            localhost.Service1    myService = new localhost.Service1();
            string    srcReturn = myService.LongOperation(5000);
            labelDisplay.Text = srcReturn;
            statusBar1.Text = "Synchronous call completed.";
        }

        private void buttonAsynch_Click(object sender, System.EventArgs e)
        {
            // runs the web service asynchronously through the Service.BeginXXX method.
            statusBar1.Text = "Running the query...";
            localhost.Service1    myService = new localhost.Service1();
            // create a wrapper that represents the callback that should be called when operation is done.
            AsyncCallback        callBack = new AsyncCallback(MyClientCallback);
            // call the web service asynchronously passing in our callback.
            IAsyncResult        asyncRes = myService.BeginLongOperation(5000, callBack, myService);
            labelDisplay.Text = "";

            // just setting up a timer to show the UI isn't blocking on the web service call.
            seconds = 0;
            timer1.Enabled = true;
        }

        public void MyClientCallback(IAsyncResult asyncResult)
        {
            // this method gets called when the web service has finished running.
            localhost.Service1    myService = (localhost.Service1)asyncResult.AsyncState;
            // call the End method to get the return value from the service.
            string    srvResult = myService.EndLongOperation(asyncResult);
            timer1.Enabled = false;

            labelDisplay.Text = srvResult;
            statusBar1.Text = "Async call completed.";
        }

        private void timer1_Tick(object sender, System.EventArgs e)
        {
            // just update some UI element.
            seconds++;
            statusBar1.Text = "Executing (" + seconds.ToString() + ").";
        }
    }
}


First, there's a method that calls the web service synchronously, buttonSync_Click. This is provided so that we can see how a web service is normally called and for testing purposes. It's always easier to test and debug the synchronous version of the call. Once we're sure that it's working correctly, we can switch to the asynchronous version. Also, it allows us to see behavior of calling the service in this way. If you run the synchronous version, you will notice the the UI thread is locked and non-responsive until the webmethod returns.

Asynchronous Call Explained
In the .NET Framework, all web services wrappers provide a synchronous and asynchronous set of calls by default. The synchronous call is named exactly the same as the webmethod name (in our case it's LongOpertion). The asynchronous one is divided into two methods: BeginLongOpertion and EndLongOperation. BeginLongOperation is called to start the asynchronous invocation. We need to provide, as parameters, a callback that the .NET Framework will invoke when the webmethod call completes and an instance of the web service (this is the object that's passed in as part of the IAsyncState). And, of course, any parameters that are passed into the webmethod call must also be passed into BeginLongOperation, in our case that's the sleepLength in milli-seconds.

The code for calling a Web Service asynchronously is relatively easy, it just requires a basic understanding of the callback mechanism in the .NET Framework. The .NET Framework defines the prototype for a callback method as follows:

  
    public void Callback(IAsyncResult asyncResult);

Any method that you want to be a callback needs to conform to that prototype. As you can see in the code above, MyClientCallback is the callback we use to get notified when the webmethod is done running. The callback method always passes in an IAsyncResult parameter, which you use to get back at the Web Service that was called in the original BeginLongOperation call. And, in the callback method, you can write any code you need to respond to the completion of the call. This will include handling errors that may have been returned from the Web Service call.

The EndLongOperation call needs to be made in the callback method to bring the invocation to completion and to get the return variable and any output parameters passed by reference.

Finally, the code for the timer is just there to show the UI updating and running concurrently with the long web service call.

Conclusion
The .NET Framework provides a full-featured implementation of web services for both the client and server. It comes with a mechanism for calling web services asynchronously whenever the user requires it. For example, when operations will require a long time and you don't want to lock up your user interface for that entire period, especially since all your client is doing is waiting for the webmethod to return (all the real processing is happening back on the server). Therefore, the asynchronous call allows you to do other processing on the client.
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值