我如何等待异步WCF服务完成?

时间:2010-10-28 20:59:10

标签: wcf asynchronous

这个问题几乎总结了一下。我有一个WCF服务,我想等到它完成其他事情,但它必须一直到它完成。我的代码看起来像这样。谢谢!

    private void RequestGeoCoordinateFromAddress(string address)
    {
        GeocodeRequest geocodeRequest = new GeocodeRequest();

        GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");

        geocodeService.GeocodeCompleted += new EventHandler<GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);

        // Make the geocode request
        geocodeService.GeocodeAsync(geocodeRequest);

        //if (geocodeResponse.Results.Length > 0)
        //    results = String.Format("Latitude: {0}\nLongitude: {1}",
        //      geocodeResponse.Results[0].Locations[0].Latitude,
        //      geocodeResponse.Results[0].Locations[0].Longitude);
        //else
        //    results = "No Results Found";

        // wait for the request to finish here, so I can do something else
        // DoSomethingElse();
    }

    private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
    {
        bool isErrorNull = e.Error == null;
        Exception error = e.Error;

        try
        {
            double altitude = e.Result.Results[0].Locations[0].Latitude;
            double longitude = e.Result.Results[0].Locations[0].Longitude;

            SetMapLocation(new GeoCoordinate(altitude, longitude));
        }
        catch (Exception ex)
        {
            // TODO: Remove reason later
            MessageBox.Show("Unable to find address. Reason: " + ex.Message);
        }
    }

5 个答案:

答案 0 :(得分:3)

WCF支持一种模式,用于呼叫具有异步开始呼叫,以及相应的结束呼叫。

在这种情况下,异步方法将在客户端的界面中如下:

[ServiceContract]
interface GeocodeService
{
     // Synchronous Operations
     [OperationContract(AsyncPattern = false, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
     GeocodeResults Geocode(GeocodeRequestType geocodeRequest);

     // Asynchronous operations
     [OperationContract(AsyncPattern = true, Action="tempuri://Geocode", ReplyAction="GeocodeReply")]
     IAsyncResult BeginGeocode(GeocodeRequestType geocodeRequest, object asyncState);
     GeocodeResults EndGeocode(IAsyncResult result);
}

如果使用带有异步调用选项的 svcutil 生成客户端界面,您将自动获得所有这些。如果您不使用自动生成客户端代理,也可以手动创建客户端界面。

结束呼叫将阻止,直到呼叫完成。

IAsyncResult asyncResult = geocodeService.BeginGeocode(geocodeRequest, null);
//
// Do something else with your CPU cycles here, if you want to
//

var geocodeResponse = geocodeService.EndGeocode(asyncResult); 

我不知道你使用接口声明做了什么来获得GeocodeAsync功能,但是如果你可以将它重新加入到这种模式中,你的工作会更容易。

答案 1 :(得分:1)

您可以使用ManualResetEvent

private ManualResetEvent _wait = new ManualResetEvent(false);

private void RequestGeoCoordinateFromAddress(string address)
{
    ...
    _wait = new ManualResetEvent(false);
    geocodeService.GeocodeAsync(geocodeRequest); 
    // wait for maximum 2 minutes
    _wait.WaitOne(TimeSpan.FromMinutes(2));
    // at that point the web service returned
}

private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
   ...
   _wait.Set();
}

显然这样做绝对没有意义,所以这里的问题是:为什么你需要这样做?如果要阻止主线程,为什么要使用异步调用?为什么不直接使用直接电话?

通常,在使用异步Web服务调用时,您不应阻止主线程,而是在异步回调中完成处理结果的所有工作。根据应用程序的类型(WinForms,WPF),您不应忘记GUI控件只能在主线程上更新,因此如果您打算在回调中修改GUI,您应该使用适当的技术(InvokeRequired,... )。

答案 2 :(得分:1)

不要将此代码用于Silverlight:

private ManualResetEvent _wait = new ManualResetEvent(false);

private void RequestGeoCoordinateFromAddress(string address)
{
    ...
    _wait = new ManualResetEvent(false);
    geocodeService.GeocodeAsync(geocodeRequest); 
    // wait for maximum 2 minutes
    _wait.WaitOne(TimeSpan.FromMinutes(2));
    // at that point the web service returned
}

private void geocodeService_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
{
   ...
   _wait.Set();
}

当我们调用_wait.WaitOne(TimeSpan.FromMinutes(2))时,我们阻止了UI线程,这意味着服务调用永远不会发生。在后台,对geocodeService.GeocodeAsync的调用实际上放在消息队列中,并且仅在线程未执行用户代码时才会执行。如果我们阻止线程,则永远不会发生服务调用。

Synchronous Web Service Calls with Silverlight: Dispelling the async-only myth

答案 3 :(得分:0)

Visual Studio 11 Beta使用async-await包含C#5。

请参阅Async CTP - How can I use async/await to call a wcf service?

它可以以“同步样式”编写异步客户端。

答案 4 :(得分:0)

我看到一个人确实使用了ManualReset和waitAll,但他必须将所有代码包装在ThreadPool中。 这是非常糟糕的主意......认为它有效