代码(内容参考于http://msdn2.microsoft.com/zh-cn/library/wyd0d1e5(VS.80).aspx):
Imports System
Imports System.Runtime.Remoting.MessagingPublic Class TestCallback
    Public Shared Sub Main()
        ' 传入参数的设定
        Dim factorizableStr As String = "20000011"        ' XML Web Service的实例生成
        Dim pf As JyuchuServices = New JyuchuServices        ' Instantiate an AsyncCallback delegate to use as a 
        ' parameter
        ' in the BeginFactorize method.
        Dim cb As AsyncCallback
        cb = New AsyncCallback(AddressOf TestCallback.FactorizeCallback)        ' Begin the Async call to Factorize, passing in the
        ' AsyncCallback delegate and a reference to our instance
        ' of PrimeFactorizer.
        Dim ar As IAsyncResult = pf.BeginGetMessage(factorizableStr, cb, pf)        ' Keep track of the time it takes to complete the async call as
        ' the call proceeds.
        Dim start As Integer = DateTime.Now.Second
        Dim currentSecond As Integer = start
        Do While (ar.IsCompleted = False)
            If (currentSecond < DateTime.Now.Second) Then
                currentSecond = DateTime.Now.Second
                Console.WriteLine("Seconds Elapsed..." & _
                      (currentSecond - start).ToString())
            End If
            Console.WriteLine("unfinished")
        Loop        ' Once the call has completed, you need a method to ensure the
        ' thread executing this Main function 
        ' doesn't complete prior to the callback function completing.
        Console.Write("Press Enter to quit")
        Dim quitchar As Integer = Console.Read()
    End Sub    ' Set up the call-back function that is invoked by the proxy 
    ' class when the asynchronous operation completes.
    Public Shared Sub FactorizeCallback(ByVal ar As IAsyncResult)        ' You passed in the instance of PrimeFactorizer in the third
        ' parameter to BeginFactorize, which is accessible in the
        ' AsyncState property.
        Dim pf As JyuchuServices = ar.AsyncState
        Dim results As String        ' Get the completed results.
        results = pf.EndGetMessage(ar)        'Output the results.
        Console.Write("factors into: " & results)
    End Sub
End Class问题:
    根据msdn上的例子,我想用上面的代码实现异步回调方法,但程序运行时,始终走不到FactorizeCallback方法,也就是没有实现回调,ar.IsCompleted始终为false,程序就卡在Do While (ar.IsCompleted = False)这个循环体里。
    用sniff监查XML Web Service服务器,发现Service已经接收到了请求,并且将正确信息返回给客户端了,但客户端的IAsyncResult的IsCompleted却始终为false,不知是为什么?
    在上述代码的Dim ar As IAsyncResult = pf.BeginGetMessage(factorizableStr, cb, pf)语句后,加一句ar.AsyncWaitHandle.WaitOne()时,FactorizeCallback方法被回调,很奇怪,如此一来实际上是用等待方法实现了异步,回调方法应该是不需要直接写等待语句的,BeginGetMessage异步开始后,直接就会运行其以下的其他代码,当IsCompleted为true时,程序会自动执行(回调)FactorizeCallback方法,不知道我的理解是否正确?
    请各位朋友给我点思路和方法,我上面的代码不能实现回调,问题到底出在哪里?在不加入WaitOne()时,如何来真正运用回调方法?
    问题较急,谢谢各位了!

解决方案 »

  1.   

    其实异步调用webservice不是很复杂,网上也有很多的例子。你参看如下两个例子
    http://www.codeproject.com/cs/webservices/async_xmlws.asp
    http://www.codeproject.com/cs/webservices/AdvAsynchWebService.asp
      

  2.   

    回调方法应该是不需要直接写等待语句的,BeginGetMessage异步开始后,直接就会运行其以下的其他代码
    --------------------------------------------------------------
    所以说 Begin 方法还没返回 IAsyncResult 就进入Do While循环体了
    ar.IsCompleted 就一直为 False
      

  3.   

    TO:chendazhi(不务正业) Dim ar As IAsyncResult = pf.BeginGetMessage(factorizableStr, cb, pf)语句执行后,应该马上就返回IAsyncResult了吧,然后就可以在 Begin 方法返回的 IAsyncResult 上检查 IsCompleted 属性。如果客户端已收到服务器的响应,该值将设置为 true。否则将始终为false。
    ↓以下代码是用wsdl自动生成的proxy代码,请作为参考-_-'------------------------------------------------------------------------------
    ' <autogenerated>
    '     This code was generated by a tool.
    '     Runtime Version: 1.1.4322.2032
    '
    '     Changes to this file may cause incorrect behavior and will be lost if 
    '     the code is regenerated.
    ' </autogenerated>
    '------------------------------------------------------------------------------Option Strict Off
    Option Explicit OnImports System
    Imports System.ComponentModel
    Imports System.Diagnostics
    Imports System.Web.Services
    Imports System.Web.Services.Protocols
    Imports System.Xml.Serialization'
    '由wsdl自动生成。Version=1.1.4322.2032。
    ''<res/>
    <System.Diagnostics.DebuggerStepThroughAttribute(),  _
     System.ComponentModel.DesignerCategoryAttribute("code"),  _
     System.Web.Services.WebServiceBindingAttribute(Name:="JyuchuServicesSoap", [Namespace]:="http://localhost/JyuchuWebService/JyuchuServices")>  _
    Public Class JyuchuServices
        Inherits System.Web.Services.Protocols.SoapHttpClientProtocol
        
        '<res/>
        Public Sub New()
            MyBase.New
            Me.Url = "http://***.***.***.***/JyuchuWebService/JyuchuServices.asmx"
        End Sub
        
        '<res/>
        <System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://localhost/JyuchuWebService/JyuchuServices/GetMessage", RequestNamespace:="http://localhost/JyuchuWebService/JyuchuServices", ResponseNamespace:="http://localhost/JyuchuWebService/JyuchuServices", Use:=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle:=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)>  _
        Public Function GetMessage(ByVal OrderNumber As String) As String
            Dim results() As Object = Me.Invoke("GetMessage", New Object() {OrderNumber})
            Return CType(results(0),String)
        End Function
        
        '<res/>
        Public Function BeginGetMessage(ByVal OrderNumber As String, ByVal callback As System.AsyncCallback, ByVal asyncState As Object) As System.IAsyncResult
            Return Me.BeginInvoke("GetMessage", New Object() {OrderNumber}, callback, asyncState)
        End Function
        
        '<res/>
        Public Function EndGetMessage(ByVal asyncResult As System.IAsyncResult) As String
            Dim results() As Object = Me.EndInvoke(asyncResult)
            Return CType(results(0),String)
        End Function
    End Class
      

  4.   

    Dim ar As IAsyncResult = pf.BeginGetMessage(factorizableStr, cb, pf)语句执行后,应该马上就返回IAsyncResult了吧,然后就可以在 Begin 方法返回的 IAsyncResult 上检查 IsCompleted 属性。如果客户端已收到服务器的响应,该值将设置为 true。否则将始终为false。
    -------------------------------------------------------------
    Begin只是异步的开始,相当于thread.start();
    在没得到服务器的响应前,主线程就到do while 了而用ar.AsyncWaitHandle.WaitOne(),则主线程会在这里等待,直到服务器响应。
      

  5.   

    to:chendazhi(不务正业) 
    我提问的代码里之所以写了do while 语句,就是为了等待线程收到服务器的响应,用do while 语句来循环等待,否则还未收到服务器的响应,程序就运行结束了,我用do while 循环来等,但却始终(永远)等不到服务器的响应,也就是IAsyncResult的IsCompleted始终(永远)为false,不知道是为什么?to:Knight94(愚翁)
    谢谢你的例子。
    http://www.codeproject.com/cs/webservices/async_xmlws.asp里的代码我已经在本机运行了,对于异步回调是成功的,能实现的,但我比较了自己写的代码,没有发现有什么不一样之处(无非一个用C#语言,我用的是VB.net语言),难道web service处会有问题?那为什么用异步等待的方法却是可以实现的,我非常的困惑,请各位提供我思路和方法,谢谢!!
      

  6.   

    ar.AsyncWaitHandle.WaitOne()你把这句换成Thread.Sleep(5000)看看http://blog.csdn.net/chendazhi/archive/2006/04/21/671627.aspx
      

  7.   

    to http://www.codeproject.com/cs/webservices/async_xmlws.asp里的代码我已经在本机运行了,对于异步回调是成功的,能实现的,但我比较了自己写的代码,没有发现有什么不一样之处(无非一个用C#语言,我用的是VB.net语言),难道web service处会有问题?那为什么用异步等待的方法却是可以实现的,我非常的困惑,请各位提供我思路和方法,谢谢!!对于你的问题,你可以如下进行调试,要么单步调试,要么写日志文件,这些方法都是为了看看程序的处理流程是什么样的,即你的程序可能有细微的问题,如果能找到出问题的代码段,就比较好分析了。
    你以上的代码这么多,外人看来很难分析出结果。
      

  8.   

    to:Knight94(愚翁) & chendazhi(不务正业) 
    我用C#代替VB.net写,尽然能回调了。
    下面是用C#和VB.net实现的代码,麻烦比较一下,到底哪里有问题?using System;
    using System.Runtime.Remoting.Messaging;public class TestProxy
    {
    private static bool bEnd=false;

    public static void JyuchuServicesCallback(IAsyncResult arResult)
    {
    JyuchuServices js=(JyuchuServices)arResult.AsyncState;
    // call "EndGetMessage" and get the result..
    String strResult = js.EndGetMessage(arResult);
    // show the result of the webservice call..
    Console.WriteLine("Async. WebService call " + strResult);
    // set flag so that application can terminate...
    bEnd=true;
    }

    public static void Main()
    {
    JyuchuServices js = new JyuchuServices();

    AsyncCallback acb = new AsyncCallback(TestProxy.JyuchuServicesCallback); js.BeginGetMessage("20000011",acb,js);

    Console.WriteLine("Waiting for webservice to end..");
    while(bEnd==false);
    Console.WriteLine("Over!");
    }
    };
    ------------------------------------------------------------------------------
    Imports System
    Imports System.Runtime.Remoting.MessagingPublic Class TestCallback
        Private Shared bEnd As Boolean = False    Public Shared Sub JyuchuServicesCallback(ByVal ar As IAsyncResult)
            Dim js As JyuchuServices = ar.AsyncState
            ' call "EndGetMessage" and get the result..
            Dim results As String = js.EndGetMessage(ar)
            ' show the result of the webservice call..
            Console.WriteLine("Async. WebService call " & results)
            ' set flag so that application can terminate...
            bEnd = True
        End Sub    Public Shared Sub Main()
            Dim js As JyuchuServices = New JyuchuServices        Dim acb As AsyncCallback = New AsyncCallback(AddressOf TestCallback.JyuchuServicesCallback)        js.BeginGetMessage("20000011", acb, js)        Console.WriteLine("Waiting for JSwebservice to end..")
            While (bEnd = False)
            End While
            Console.Write("Over!")
        End Sub
    End Class
    我看上面的两段代码虽然用不同语言实现,但从语义上应该是完全一样的,为什么用C#写的代码能实现机能,而用VB.net写的却不行,真是非常的奇怪,请各位再帮忙看看,谢谢了!!
      

  9.   

    什么原因我真的不知道。
    看看C#和VB.net的Web.Config就知道有点差别了,就连注释一个英文一个中文
      

  10.   

    应该是.net 的问题。我google了一下,好似也有人说有类似的问题。 循环查看的时候要加上doevents,不过微软好像没有说明文档。http://geekswithblogs.net/thibbard/archive/2004/08/16/9783.aspx
      

  11.   

    非常感谢<Montaque(每天回答两个问题)>的回答,我试了一下,在运用事件触发后,用VB.net写的回调方法也可以实现了,我的问题得以解决。
    但为何要在触发事件后才能解决问题,至于具体的原因还不是很清楚。总结一下:
    我在前面提问了关于C#和VB.net写出的相同语义的回调方法,为何结果会不同?
    经过这几天的实验和各位朋友的提醒,可能原因如下:
    1、C#写出语言的执行速度要比VB.net的快的多。
    2、由于速度上的偏差,导致相同语义的代码,运行的结果会不一样(特别在异步运用时,尤明显)
    3、由于VB.net生成的代码执行速度慢,在还未得到(或处理到)WebService的返回结果时,程序就已经执行到了while循环体里,此时却消耗了大量的cpu资源,导致Begin的异步线程无法完成和ar.IsCompleted始终为false。C#生成的代码执行速度快,在未执行到while语句前,侥幸能异步回调。
    4、我写的代码不是很好,在异步线程Begin后就直接要等待结果的程序(逻辑)不适合异步的回调方法,如果要用的话,可能就要用到System.Threading.Thread.Sleep方法,但这样的话Sleep时间的长短将又是一个问题。在我看来还不如用异步等待方法来的直接和有效。终于解决了问题,松了一口气,客户要求用回调方法实现,没有办法啊,但毕竟我也学了一些东西,最后再感谢一下各位朋友的回答。