巨大的石头

在这里寻找精彩人生

导航

异步调用WEBSERVICE

今天异步调用WebService时,发现了一个问题:同样的webservice,使用Winform、Web Applcation Project与使用Web调用时,生成的代理却不太一样。

截图01                                 截图01

       Winform调用的代理View                                                       Web调用的代理View

webservice中有一个服务方法

[WebMethod]
public string GetTime()
{
     return DateTime.Now.ToString();
}

 但是看上图,左边的代理中却没有异步调用的函数public System.IAsyncResult BeginGetTime(System.AsyncCallback callback, object asyncState)。

具体的原因我查了下,微软的回答是:

It is by design that the proxy generator in VS 2005 project only generates new style async proxy, and the old style async proxy (Being/End function) has been abandoned. For backward compactibility reasons, the old style code is still generated along with the new style function, it the project is upgraded from old VS. The web site project always generates both style code in the proxy.
However, if you still need the old style async proxy in a new VS 2005 project, there is a workaround. You can set a project level property WebReference_EnableLegacyEventingModel to be true.
To do that, you need unload the project from VS, and edit the project file directly in an editor. (Please backup one in case you do something wrong.)
In the first section of PropertyGroup, you will see many properties like:
    <ProjectGuid>{F4DC6946-F07E-4812-818A-F35C5E34E2FA}</ProjectGuid>
    <OutputType>Exe</OutputType>
...
Don't change any of those, but do add an extra property just like the OutputType into that section like:
    <WebReference_EnableLegacyEventingModel>true</WebReference_EnableLegacyEventingModel>
Ignore the warning from the xml editor, save the file, and reload the project into VS.
After that, you have to regenate all proxy code (by updating the reference, or running the custom tool on the .map file)

原来(Being/End function) 这种方法已经被抛弃了。

但是,不管是Winform还是Web调用,都是可以对Webservice进行异步调用的。

方法有两种:

1、Begin/End方法(虽然被丢弃)。

2、事件驱动方法。

下面来具体谈谈这两种方法;

1、Begin/End方法

使用 Begin/End 模式实现进行异步方法调用的 Web 服务客户端
客户端如何知道何时调用 End 方法呢?根据 .NET Framework 的定义,有两种方法可以使客户端确定这一点:

客户端调用方式1等待方法:使用 WaitHandle 类的方法之一使客户端等待方法完成。

客户端调用方式2回调方法:向 Begin 方法传递一个回调函数,在该方法完成处理后再调用该函数来检索结果。

注意:无论客户端选择两种方法中的哪一种与 Web 服务进行异步通信,收发的 SOAP 消息都与通过同步代理方法生成的 SOAP 消息相同。也就是说,仍然只有一个 SOAP 请求和 SOAP 响应通过网络发送和接收。代理类通过使用与客户端调用 Begin 方法时使用的线程不同的线程来处理 SOAP 响应,从而实现该目的。因此,在代理类接收和处理 SOAP 响应时,客户端可以在其线程上继续执行其他工作。

webservice代码:

[WebService(Namespace = "http://tempuri.org/" ,Name="TheFirstWebservice",Description="This is a test webservice")]
[WebServiceBinding(ConformsTo = WsiProfiles.None)]
public class WebService : System.Web.Services.WebService {

    public WebService () {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod(CacheDuration=10)]
    public string HelloWorld() {
        return "Hello World";
    }
    [WebMethod(Description="用于测试DataSet")]
    public DataSet GetData()
    {
        DataTable dt = new DataTable();
        dt.Columns.Add(new DataColumn("Name",typeof(string)));
        dt.Columns.Add(new DataColumn("Age", typeof(int)));
        DataRow dr = dt.NewRow();
        dr["Name"] = "陈云龙";
        dr["Age"] = 20;
        dt.Rows.Add(dr);
        dr = dt.NewRow();
        dr["Name"] = "赵刚";
        dr["Age"] = 24;
        dt.Rows.Add(dr);
        DataSet ds= new DataSet("DefaultSet");
        ds.Tables.Add(dt);
        System.Threading.Thread.Sleep(3000);
        return ds;
    }
    [WebMethod]
    public string GetTime()
    {
        return DateTime.Now.ToString();
    }
    [WebMethod(MessageName="GetFormatTime",CacheDuration=10)]
    public string GetTime(string format)
    {
        return DateTime.Now.ToString(format);
    }
}

客户端调用方式1(Begin/End 模式的回调方法)

解说(解说来自MSDN)

<!--[if !supportLists]-->
          定义实现 AsyncCallback 委托的回调函数。
public static void FactorizeCallback(IAsyncResult ar)

<!--[if !supportLists]-->
      实例化 AsyncCallback 委托。
<!--[endif]-->
AsyncCallback cb = new AsyncCallback(TestCallback.FactorizeCallback);

<!--[if !supportLists]--> <!--[endif]-->调用 Begin 方法,将回调函数作为第二个参数传递,将提供状态的对象(在本示例中是 PrimeFactorizer 的客户端实现)作为第三个参数传递。
IAsyncResult ar = pf.BeginFactorize(factorizableNum, cb, pf);

<!--[if !supportLists]--> <!--[endif]-->在 Begin 方法返回的 IAsyncResult 上检查 IsCompleted 属性。如果客户端已收到服务器的响应,该值将设置为 true。
<!--[if !supportLists]--> <!--[endif]-->在回调函数中访问状态对象。IAsyncState 参数的 AsyncState 属性将该对象作为第三个参数传递给 Begin 方法。
PrimeFactorizer pf = (PrimeFactorizer) ar.AsyncState;

<!--[if !supportLists]--> <!--[endif]-->在回调函数中,对上一步中获取的状态对象调用 End 方法。
long[] results = pf.EndFactorize(ar);

示例:

 protected void Button1_Click(object sender, EventArgs e)
    {
        AsyncCallback callback = new AsyncCallback(GetDataCallBack);
        localhost.TheFirstWebservice webservice = new localhost.TheFirstWebservice();
        IAsyncResult result = webservice.BeginGetData(callback, webservice);
        //当异步调用没有结束时
        while (result.IsCompleted)
        {
            //客户端代码
         }
    }
    public void GetDataCallBack(IAsyncResult result)
    {
        localhost.TheFirstWebservice webservice = (localhost.TheFirstWebservice)result.AsyncState;
        DataSet ds = webservice.EndGetData(result);
    }

客户端调用方式2(Begin/End 模式的等待方法)

解说(解说来自MSDN)

WaitHandle 类实现下列支持等待同步对象得到信号通知的方法:WaitOne、WaitAny 和 WaitAll。当同步对象得到信号通知时,表示等待指定资源的线程此时可以访问该资源了。Web 服务客户端通过 Begin 方法返回的 IAsyncResult 对象的 AsyncWaitHandle 属性,来访问 WaitHandle 对象。

具体做法:

<!--[if !supportLists]-->1、 <!--[endif]-->Web 服务客户端调用所生成的代理类的 Begin 方法。

IAsyncResult ar = pf.BeginFactorize(factorizableNum, null, null);

<!--[if !supportLists]-->2、 <!--[endif]-->Web 服务客户端通过返回的 IAsyncResult 的 AsyncWaitHandle 属性来访问 WaitHandle 对象。

ar.AsyncWaitHandle.WaitOne()

<!--[if !supportLists]-->3、 <!--[endif]-->等待方法返回后,客户端调用 End 方法来获取结果。

results = pf.EndFactorize(ar);

示例:

 protected void Button1_Click(object sender, EventArgs e)
    {
        localhost.TheFirstWebservice webservice = new localhost.TheFirstWebservice();
        IAsyncResult result = webservice.BeginGetData(null, null);
        result.AsyncWaitHandle.WaitOne();
        DataSet ds = webservice.EndGetData(result);
    }

2、事件驱动方法

解说:

Web 服务代理类中的每个 Web 方法都具有一个异步的对应版本。代理类自动生成每个 Web 方法的异步方法和对应事件。当异步方法被调用时,它将在另一个线程上执行,并在返回时引发对应的事件。您可以为异步方法的对应事件创建一个处理程序,从而 在它返回时执行代码。

此模型可以简化生成多线程应用程序的过程,因为您不必自己实现复杂的多线程代码。

具体做法:

<!--[if !supportLists]-->1、 <!--[endif]-->创建MethodCompleted 事件。

private void HelloWorldCompleted(Object sender,

    localhost.HelloWorldCompletedEventArgs Completed)

    {

        // Insert code to implement the method here

    }

<!--[if !supportLists]-->2、 <!--[endif]-->向该事件的处理程序列表添加 MethodCompleted 事件处理程序。

myWebService.HelloWorldCompleted += new localhost.HelloWorldCompletedEventHandler(HelloWorldCompleted);<!--[if !supportLists]-->3、 <!--[endif]-->使用该方法的 MethodAsync 形式调用 Web 方法.

HelloWorldAsync();

示例

webservice代码同上

客户端调用方式:

 private void BtnGoAsync_Click(object sender, EventArgs e)
        {
            //创建代理类对象
            localhost.TheFirstWebservice objService = new WebServiceForm.localhost.TheFirstWebservice();
            objService.HelloWorldCompleted += new localhost.HelloWorldCompletedEventHandler(HelloWorldCompletedFunc);
            objService.HelloWorldAsync("px");
            TxtAsync1.Text = DateTime.Now.ToString("mm:ss.ffff");
        }
        public void HelloWorldCompletedFunc(object sender, localhost.HelloWorldCompletedEventArgs e)
        {
            TxtAsync2.Text = e.Result;
        }

以上解说参考http://blog.csdn.net/Wgf2006/archive/2008/04/09/2270332.aspx

posted on 2010-05-27 13:07  巨大的石头  阅读(9085)  评论(1编辑  收藏  举报

打赏