2012-01-13 2 views
0

мне нужно перевести исключение, исходящее из Task<T> таким же образом, что выполнение следующих действий будет для нормального синхронного кода:исключения переводили недействительные задачи с Task Parallel Library а-лей ждет

try { 
    client.Call(); 
} catch(FaultException ex) { 
    if (ex.<Some check>) 
     throw new Exception("translated"); 
} 

Тем не менее, я хочу для этого асинхронно, т. е. Call выше на самом деле Task CallAsync().

Так в C# 5 мой метод будет выглядеть следующим образом:

async Task CallAndTranslate() 
{ 
    try{ 
     await client.CallAsync(); 
    } catch(FaultException ex) { 
     if (ex.FaultCode ...) 
      throw new Exception("translated"); 
    } 
} 

Но я использую C# 4 сейчас.

Итак, что я могу сделать, учитывая, что я хочу вызвать задачу, но с ошибкой (TPL) перевести, а затем разоблачить все это еще раз как Task<T>?

  • первоначально исходящая из WebService WCF, но это не важно здесь

EDIT: Немного более конкретный способ сказать это:

public class TranslatingExceptions 
{ 
    public Task ApiAsync() // The inner layer exposes it exactly this way 
    { 
     return Task.Factory.StartNew(()=>{ throw new Exception("Argument Null");}); 
    } 

    public Task WrapsApiAsync() // this layer needs to expose it exactly this way 
    { 
     // async preview pseudocode for what I need to do        
     try { 
      await ApiAsync(); 
     } catch (Exception exception){ 
      if(exception.Message == "Argument Null" ) 
       throw new ArgumentNullException(); 
     } 
    } 

    [Fact] 
    public void Works() 
    { 
     var exception = Record.Exception(() => 
      WrapsApiAsync().Wait()); 
     Assert.IsType<ArgumentNullException>(exception.InnerException); 
    } 
} 

Как бы реализовать WrapsApiAsync() без необходимости C# 5 ?

ответ

1

Итак, теперь, когда я совершенно ясно, что вы ищете, здесь все, что вам нужно будет сделать, чтобы построить эквивалент в 4.0:

public class TranslatingExceptions 
{ 
    public Task ApiAsync() // The inner layer exposes it exactly this way 
    { 
     return Task.Factory.StartNew(()=>{ throw new Exception("Argument Null");}); 
    } 

    public Task WrapsApiAsync() // this layer needs to expose it exactly this way 
    { 
     // Grab the task that performs the "original" work 
     Task apiAsyncTask = ApiAsync(); 

     // Hook a continuation to that task that will do the exception "translation" 
     Task result = aspiAsync.ContinueWith(antecedent => 
     { 
      // Check if the antecedent faulted, if so check what the exception's message was 
      if (antecedent.IsFaulted 
       && antecedent.Exception.InnerException.Message == "Argument Null") 
      { 
       throw new ArgumentNullException(); 
      } 
     }, 
     TaskContinuationOptions.ExecuteSynchronously); 

     // Now we return the continuation Task from the wrapper method so that the caller of the wrapper method waits on that 
     return result; 
    } 

    [Fact] 
    public void Works() 
    { 
     var exception = Record.Exception(() => 
             WrapsApiAsync().Wait()); 

     Assert.IsType<ArgumentNullException>(exception.InnerException); 
    } 
} 

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

+0

Спасибо за высокую оценку. Попытайтесь, хотя я могу, хотя, я не могу присоединиться к точкам от вашего ответа до моей проблемы. Скорее всего, это потому, что мой последний CLR через чтение C# - полтора года назад и/или я не понимаю 1 или более важных принципов. В моей реальной проблеме я передаю задачу обратно через несколько слоев в цепочке. Мне бы очень хотелось, чтобы все мои API-интерфейсы оставались чистым единственным методом, возвращающим задачу, которая легко объединяется, а не должна использовать стиль APM на всем протяжении пути. Я сомневаюсь, что это то, что вы предлагаете! –

+0

Все в порядке, что вы используете задачи внутри, только на уровне WCF вам нужно «переключиться» на модель APM, потому что в данный момент все стеки WCF понимают и предлагают интеграцию с точки зрения получения работы от одной из это потоки ввода-вывода. Я буду бить вместе образец для вас. –

+0

Хммм. Я не должен был упоминать WCF, поскольку это не главное (я использую WCF только в самой внутренней точке). Но теперь, когда я это сделаю, я сам объясню. Я использую [напряжение XXXTaskAsync на моем прокси-сервере WCF] (http://qa.social.msdn.microsoft.com/Forums/en-US/async/thread/74e02263-da5e-487d-b57b-4f0c90342b7d), чтобы дать возможность выполнить работу как «Задача». Проблема в том, как 3 слоя из этого я завершаю задачу в чем-то (другая задача, которая?), Которая может перевести исключение, если она есть. –