1

我正在使用 WCF 异步方法。

当我尝试返回回调函数的值时遇到问题。

有哪些可能的解决方法?(使用 .net 4.0,但不是 4.5

    public static Object LoadInfo()
    {
        var service = new SomeWcfService();
        service.BeginGetInfo(CallbackMethod, service);

        // HOW TO GET INFROMATION FROM CALLBACK??
        return INFORMATION;
    }

    private static void CallbackMethod(IAsyncResult ar)
    {
        // HOW TO PASS INFROMATION TO LoadInfo??
        var INFORMATION = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
    }

注意:所有工作都应该是异步的。

谢谢。

4

2 回答 2

1

最好设计使用异步模式而不是反对它。

但是,如果您必须同步访问异步方法,则可以使用信号量来阻塞调用线程,直到异步方法返回。

public static Object LoadInfo()
{
    // this is our semaphore
    var blocker = new AutoResetEvent();
    object result = null;

    var service = new SomeWcfService();
    // use a lambda instead of a method as the callback.
    // this will result in a closure where we can access the result and blocker variables
    service.BeginGetInfo(x => 
    {
        // We are on a different thread within this lambda
        result = (x.AsyncState as SomeWcfService).EndGetInfo(ar);
        // release anybody calling blocker.WaitOne
        blocker.Set(); 
    }, service);

    // we are still on the original thread here, and
    // BeginGetInfo has possibly not yet executed, so we must wait until Set is called
    blocker.WaitOne(Timeout.Infinite); 
    return result;
}

这很少是一个好的设计选择。异步模式更适合响应式 UI。最好做这样的事情

public void LoadInfo()
{
    // Makes the UI show a loading indicator, blocking all actions except for CANCEL
    LoadingInfo = true;

    var service = new SomeWcfService();
    service.BeginGetInfo(CallbackMethod, service);
}

private void CallbackMethod(IAsyncResult ar)
{
    // the UI is now released from loading 
    LoadingInfo = false;
    // the UI is triggered to show our data
    ViewModel.Data = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);
}
于 2012-08-30T15:47:42.573 回答
1

一开始就理解异步,尤其是回调是很困难的。在您的示例中,您做出了不正确但自然的假设...

public static Object LoadInfo() 
{ 
    var service = new SomeWcfService(); 
    service.BeginGetInfo(CallbackMethod, service); 

    // HOW TO GET INFROMATION FROM CALLBACK?? 
    // ERROR: You assume you have more work to do in this method,
    // or that this is the place to return your results.
    return INFORMATION; 
} 

您在下面给出的方法是返回结果后进行工作的地方:

private static void CallbackMethod(IAsyncResult ar) 
{ 
    // HOW TO PASS INFROMATION TO LoadInfo?? 
    // OOPS! No need to pass pack to LoadInfo - it's done...
    var INFORMATION = (ar.AsyncState as SomeWcfService).EndGetInfo(ar); 
}

相反,你会想要这样的东西

public static void LoadInfo()        
{        
    var service = new SomeWcfService();        
    // begin an asynchronous service call
    // and handle the results in another method, "CallbackMethod"
    service.BeginGetInfo(CallbackMethod, service);  
    // You can do other, non-service related,
    // things here while the service call executes 
}   

然后您的其他方法处理所有结果:

private static void CallbackMethod(IAsyncResult ar)            
{            
    var results = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);  
    // Do whetever you need with results here
}    

正如威尔在他的出色回答中指出的那样(+1,好像他需要它,哈哈!),您可以使用带有 lambda 表达式的匿名方法,而不是使用单独的回调方法,例如:

public static void LoadInfo()        
{        
    var service = new SomeWcfService();        
    // begin an asynchronous service call
    // and handle the results in this anonymous method
    service.BeginGetInfo(x =>
    {
        // B. This code block will be called when the service returns with results
        var results = (ar.AsyncState as SomeWcfService).EndGetInfo(ar);  
        // Do whetever you need with results here
    }, service);  

    // A. You can do other things here while the service call executes
    // but debugging this gets more complicated because things will likely
    // occur at A before they occur at B
}

所以,Asynchronous 的总体思路是:

  • 您的程序设置并开始一个服务调用,然后继续做它想做的任何其他事情,而无需等待。提示:这是开始加载动画和/或禁用某些控件的自然位置。
  • 当您进行异步调用时,作为参数之一,您提供了一个在调用完成后运行的方法。
  • 当服务返回结果时,将运行您指定的方法来处理结果。提示:在此方法中,您可以结束加载动画,和/或重新启用您的控件,并将结果插入您的 ViewModel。
于 2012-08-30T17:45:53.793 回答