Асинхронный доступ к веб-службам в шаблонах проектирования .NET - Клиентское время простоя

ОГЛАВЛЕНИЕ

Клиентское время простоя

В тестовой службе (Листинг-1) серверный процесс обрабатывает время простоя, переданное клиентом. Касательно посредника веб-службы, он имеет свойство Timeout (унаследованное от WebClientProtocol), предназначенное для выполнения синхронного запроса. В асинхронном режиме посредник не предоставляет время простоя напрямую, вероятно, так как можно использовать Abort() (тоже из WebClientProtocol) для отмены зависшего запроса.

Иногда в асинхронной модели приходится ждать завершения запроса, и время простоя было бы желательно, тогда как сервер и его посредник не предоставляют метод времени простоя. Поэтому клиенту приходится самому разбираться с временем простоя. Повторно вызывая BeginGetStock() при запуске запроса, он возвращает следующий объект r:

IAsyncResult r = _weProxy1.BeginGetStock(symbol, null, null);

Нельзя вызывать r.AsyncWaitHandle.WaitOne(timeout, false), так как WaitOne() не освобождает текущий поток, пока он не вернет управление, так что он блокирует отмену.

Одно решение – установить цикл для опроса свойства IsCompleted IAsyncResult, моделируя время простоя. Листинг-7 показывает данный подход с совместной проверкой на время простоя и на флаг отмены.

// Листинг-7. Опрос для достижения клиентского времени простоя (wsasyExp4.txt)

// Пример 4. Опрос для достижения клиентского времени простоя (wsasyExp4.txt)

public GetStockStatus GetStock(ref string symbol)
{
    _cancel = true;
    _weProxy1 = new Service();
    IAsyncResult r = _weProxy1.BeginGetStock(symbol, null, null);   
   
    // Опрашивается здесь, если _cancel равен истине, прерывается
    // Моделируется время простоя с интервалом 10 мс.
    int i = 0;
    int n =_timeout/10;

    for (; i < n; i++)
    {
        if (_cancel)
        {
            symbol = "<" +symbol +">";
            _weProxy1.Abort();
            return GetStockStatus.Cancelled;
        }

        if (r.IsCompleted == true)
            break;

        Thread.Sleep(10);
    }               

    if (r.IsCompleted == false && i==n)
    {
        symbol = "[" +symbol +"]";
        _weProxy1.Abort();
        return GetStockStatus.TimeOut;
    }

//    если (!r.AsyncWaitHandle.WaitOne(_timeout, true))
//        return GetStockStatus.TimeOut;

    double value;
    try
    {
        value = _weProxy1.EndGetStock(r);
    }
    catch (Exception e)
    {  
       ... ... ...
    }

    ... ... ...

    symbol = value.ToString("F");
    return GetStockStatus.OK;
}

public void Cancel()
{
    _cancel = true;
}

Используется флаг _cancel в Cancel() вместо прямого вызова _weProxy1.Abort(). При завершении цикла можно определить время простоя и прервать запрос к серверу. Как только r.IsCompleted установлен в true, вызов завершается с осмысленным значением, возвращенным из _weProxy1.EndGetStock(r).

Недостаток опроса в том, что цикл потребляет много ресурсов в виде циклов центрального процесса. Тщательно следите за этим недостатком асинхронной реализации.

Вывод

Сегодня разработка программного обеспечения переходит с ранней объектно/компонентно-ориентированной модели на модель на базе служб. Асинхронные механизмы могут широко использоваться в системе на базе служб, в веб-серверах XML, в дистанционной связи .NET и в основе связи Windows в .NET 3. В данной статье представлено несколько моделей проектирования, типичные асинхронные реализации с обратными вызовами, делегатами, событиями и потоками. Затронуты два интересных аспекта – отмена и время простоя. Каждый представленный тут подход имеет свои плюсы и минусы, которые надо учитывать на практике. Хотя примеры проектов написаны на C# в .NET 1.1 и 2.0, основные методы рекомендуются для систем с разными версиями, языками и платформами.