Асинхронный доступ к веб-службам в шаблонах проектирования .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, основные методы рекомендуются для систем с разными версиями, языками и платформами.