这个问题几乎总结了一下。我有一个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);
}
}
答案 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中。 这是非常糟糕的主意......认为它有效