2015-11-04 1 views
3

Я не понимаю разницы между этими двумя реализациями вызова SendMailAsync. В большинстве случаев с первым я получаю исключение TaskCanceledException, но со вторым все работает так, как ожидалось.Причина TaskCanceledException с SendMailAsync?

Я думал, что два метода потребления будут эквивалентны, но, очевидно, я что-то упустил.

Это кажется связано, но напротив: TaskCanceledException when not awaiting

// Common SmtpEmailGateway library 
public class SmtpEmailGateway : IEmailGateway 
{ 
    public Task SendEmailAsync(MailMessage mailMessage) 
    { 
     using (var smtpClient = new SmtpClient()) 
     { 
      return smtpClient.SendMailAsync(mailMessage); 
     } 
    } 
} 

// Caller #1 code - Often throws TaskCanceledException 
public async Task Caller1() 
{ 
    // setup code here 
    var smtpEmailGateway = new SmtpEmailGateway(); 
    await smtpEmailGateway.SendEmailAsync(myMailMessage); 
} 

// Caller #2 code - No problems 
public Task Caller2() 
{ 
    // setup code here 
    var smtpEmailGateway = new SmtpEmailGateway(); 
    return smtpEmailGateway.SendEmailAsync(myMailMessage); 
} 

EDIT: Оказывается, метод Caller2 также вызывает исключения, я просто был не видя их из-за рамки WebJobs этого времени называются от. Объяснение Юваля прояснило все это и верно.

+0

Как вы называете Caller1 и Caller2? –

+0

Caller1 и Caller2 являются общедоступным методом, называемым SDK Azure WebJobs. И SDK поддерживает асинхронные методы. –

ответ

3

Разница между двумя вызовами метода заключается в том, что предыдущий асинхронно ждет, используя await при вызове. Таким образом, TaskCanceledException распространяется от внутреннего вызова SendEmailAsync, что вызвано тем фактом, что вы не ожидаете асинхронного метода в области using, что вызывает состояние гонки между удалением SmtpClient и окончанием асинхронного вызова. Хотя в последнем случае исключение инкапсулируется внутри возвращаемого объекта Task, и я не уверен, ожидаете ли вы этого или нет. Вот почему в первом вы видите исключение немедленно.

Первое, что должно быть сделано правильно ждать на SendEmailAsync внутри шлюза:

public class SmtpEmailGateway : IEmailGateway 
{ 
    public async Task SendEmailAsync(MailMessage mailMessage) 
    { 
     using (var smtpClient = new SmtpClient()) 
     { 
      return await smtpClient.SendMailAsync(mailMessage); 
     } 
    } 
} 

Затем, вы можете использовать второй метод, который позволяет избежать накладных расходов на создание государственной машины. Разница заключается в том, что вы гарантируете, что SmtpClient будет действовать только после завершения операции async.

+0

Если у меня это правильно: я никогда не должен возвращать Задачу из объекта, не ожидая ее, когда внутри этой инструкции использования объекта. Это связано с тем, что объект, скорее всего, будет удален до завершения задачи. Это правильно? –

+0

@BrianVallelunga Правильно. –

+0

И, похоже, мой метод Caller2 просто вызывал исключения, которые я не ловил, но структура WebJobs ловила и повторила попытку. –