2015-05-08 4 views
7

Я бегу Owin Самостоятельное размещение веб-Апи, с типичным контроллером так:Async Web Api Controller - Как обрабатывать отмены?

[HttpGet] 
    [Route("refresh/{secId}")] 
    [ResponseType(typeof(int))] 
    public async Task<IHttpActionResult> RefreshElement(int secId) 
    { 
     var count = await _db.Refresh(secId); 

     if (count == 0) 
      return NotFound(); 

     return Ok(count); 
    } 

Предполагая _db.Refresh() давно работает (несколько секунд), а иногда выбрасывает исключение.

Проблема я удалось воспроизвести это:

  • Запрос попадает метод, _db.Refresh увольняют от
  • Запрос отменяется (гнездо закрыто)

Результат от _db.Refresh больше не ждёт - потому что я вижу, когда он возвращает исключение, он появляется через незаметную обработку исключений TPL, когда задача GCd ...

Mayb e из-за таких взаимодействий команда .net изменила необработанную политику исключений, чтобы не срывать процессы (4.5, я думаю) ... так что хорошая модель из этой проблемы? В частности, для самостоятельного размещения WebApi с использованием OWIN - поскольку я все еще регистрирую незаметные исключения как FATAL :)

Я могу сделать _db.Refresh() взять маркер отмены, но как/когда я устанавливаю токен отмены для разъединений/отменяет в собственном хозяине webapi?

ответ

0

Вы можете справиться с запросом тайм-аута, внедряя промежуточное ПО самостоятельно.

IOwinContext имеет Request свойство, которое само по себе держит CancellationToken имени CallCancelled, который может быть опрашиваемых, чтобы увидеть, если запрос был отменен:

public class CancellationAwareOwinMiddleware : OwinMiddleware 
{ 
    public async Task Invoke(IOwinContext owinContext) 
    { 
     try 
     { 
       await Next.Invoke(owinContext); 
     } 
     catch (TaskCanceledException) 
     { 
      // Handle cancellation. 
     } 
     catch (Exception e) 
     { 
      if (owinContext.Request.CallCancelled.IsCancellationRequested) 
      { 
       // Handle cancellation. 
      } 
     } 
    } 
} 

Обратите внимание на общее положение исключения есть, потому что я не уверен, Owin будет вызывать TCE, когда запрос tge отменяется, так что полюбите токен в любом случае, чтобы быть уверенным.

Edit:

Как @usr указал мне, это решение будет обрабатывать случай Outter Task Собирается незамеченной, и это было довольно большое предположение, что я делал. Если это внутренняя задача, мне нужно будет переосмыслить решение.

+0

Это действительно решит проблему, что задача, возвращаемая 'RefreshElement', никогда не будет наблюдаться? – usr

+0

@usr Вопрос заключается в том, что 'Задача' будет незаметной, внутренней задачей или фоном. Но вы правы, я не уверен, почему я предположил, что это был выход. –

+0

Я думаю, что внутренняя задача будет наблюдаться ожиданием, которое все еще работает. Это не отменяется. Фактически 'RefreshElement' никогда не отменяется. – usr

12

Возможно, это не в полной мере ответить на ваш вопрос, но я считаю, что ответ на этот последнюю часть:

я могу сделать _db.Refresh() принимают в знак отмены, но, как/когда же я поставил токен отмены для разъединений/отменяется в собственном хостинге webapi?

Если вы добавите в свой метод действия параметр CancellationToken, инфраструктура будет поставлять его при его вызове.

[HttpGet] 
[Route("refresh/{secId}")] 
[ResponseType(typeof(int))] 
public async Task<IHttpActionResult> RefreshElement(
    int secId, CancellationToken cancellationToken) 
{ 
    var count = await _db.Refresh(secId, cancellationToken); 

    if (count == 0) 
     return NotFound(); 

    return Ok(count); 
} 

Однако обратите внимание, что есть еще небольшое окно возможностей, в котором клиент может отключиться перед выходом метода действия, в этом случае вашего TPL незаметное исключение будет по-прежнему иметь место.

+0

Отмена может произойти сразу после последнего обновления. Обновить проверяет токен, но до сбоя. Это просто уменьшает окно возможностей. Не исправить. – usr

+0

@usr Я знаю о проблеме, о которой вы говорите, и другой ответ. Я уточнил, в какой части вопроса я отвечаю. –

+0

@usr Я задаюсь вопросом, знает ли система, чтобы наблюдать за Задачей в случае, когда CancellationToken был отменен во время запроса? –

Смежные вопросы