Как я могу ждать завершения асинхронной службы WCF? - PullRequest
2 голосов
/ 29 октября 2010

Вопрос в значительной степени подводит итог.У меня есть служба 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 ]

3 голосов
/ 29 октября 2010

Существует шаблон, поддерживаемый WCF, для вызова с асинхронным вызовом begin и соответствующим вызовом end .

В этом случае асинхронные методы будут в интерфейсе клиента следующим образом:

[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 с опцией асинхронных вызовов, вы получите все это автоматически.Вы также можете вручную создать клиентский интерфейс, если не используете автоматическую генерацию клиентских прокси.

Вызов End будет блокироваться до завершения вызова.

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 голос
/ 11 июня 2011

Не используйте этот код с 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)), мы блокируем поток пользовательского интерфейса, что означает, что вызов службы никогда не принимаетместо.В фоновом режиме вызов geocodeService.GeocodeAsync фактически помещается в очередь сообщений и будет действовать только тогда, когда поток не выполняет пользовательский код.Если мы заблокируем поток, вызов службы никогда не произойдет.

Синхронные вызовы веб-службы с Silverlight: рассеивание мифа только для асинхронной обработки

1 голос
/ 29 октября 2010

Вы могли бы использовать 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();
}

Очевидно, что делать это не имеет абсолютно никакого смысла, поэтому возникает вопрос: зачем вам это нужно?Зачем использовать асинхронный вызов, если вы собираетесь заблокировать основной поток?Почему бы вместо этого не использовать прямой вызов?

Как правило, при использовании вызовов асинхронных веб-служб не следует блокировать основной поток, а выполнять всю работу по обработке результатов в асинхронном обратном вызове.В зависимости от типа приложения (WinForms, WPF) вы не должны забывать, что элементы управления графическим интерфейсом могут обновляться только в главном потоке, поэтому, если вы намереваетесь изменить графический интерфейс в обратном вызове, вы должны использовать соответствующий метод (InvokeRequired, ...).

0 голосов
/ 19 декабря 2012

Я видел, как один парень использовал ManualReset и waitAll, но ему пришлось обернуть весь код внутри ThreadPool .. Это очень плохая идея ... думал, что это работает

0 голосов
/ 05 апреля 2012

Visual Studio 11 Beta включает C # 5 с асинхронным ожиданием.

См. Async CTP - Как я могу использовать async / await для вызова службы wcf?

Это позволяет писать асинхронные клиенты в «синхронном стиле».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...