2015-05-16 5 views
4

У меня есть контроллер WebApi, который одна из частей отправляет электронные письма множеству пользователей.WebApi Controller - Send Mail Async

[HttpPost] 
[Authorize] 
[Route("{id}/Do")] 
public async Task<HttpResponseMessage> Post(int id, Model model) 
... 
    await _emailService.SendAsync(message); 
... 

Теперь метод, который отправляет электронную почту (SendGrid)

public override async Task SendAsync(MailMessage message) 
{ 
    var client = 
     new SmtpClient(SendGridServerName, SendGridServerPort) 
     { 
      Port = SendGridServerPort, 
      DeliveryMethod = SmtpDeliveryMethod.Network, 
      UseDefaultCredentials = false 
     }; 

    var credentials = new NetworkCredential(SendGridUserName, SendGridPassword); 

    client.EnableSsl = true; 
    client.Credentials = credentials; 
    message.From = new MailAddress(FromAddress); 

    await client.SendMailAsync(message); 
} 

Все работает, но очень медленно. Я ожидал, что он будет быстрым, но await _emailService.SendAsync(message); не выглядит как асинхронный. Он останавливается на некоторое время.

Любые идеи?

Благодаря

+1

Посмотрите на [WebApi Async] (http://stackoverflow.com/questions/22814134/multiple-await-async-in-net-webapi). «Один запрос может быть немного медленнее», но когда система находится под нагрузкой, она будет работать лучше. степенно-очистительный. Предполагая, что почтовый клиент является SmtpServer, вам лучше с помощью [нового потока] (http://forums.asp.net/t/1731495.aspx?SmtpClient+SendAsync+doesn+t+do+anything), поэтому ваше действие не является Не дождавшись завершения этого. – lloyd

+2

Я бы предложил использовать [SendGrid SDK] (https://github.com/sendgrid/sendgrid-csharp), у них есть методы «Async», которые используют API REST. –

+0

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

ответ

8

Что async делает, позволяя серверу запускать другие темы, в то время как ваш медленный метод выполняется асинхронно. I.e., когда вы используете await для метода async, сервер выполняет другой поток до тех пор, пока метод async не завершит выполнение, а затем продолжит выполнение потока, который называется методом async. Асинхронные действия в контроллере обрабатываются точно так же за кулисами. Таким образом, ответ от вашего действия async на браузер не произойдет, пока сообщение электронной почты async не закончится.

ПРИМЕЧАНИЕ: например, если есть проблемы с подключением к серверу электронной почты или разрешение DNS, вы обычно получаете тайм-аут через 30 секунд, поэтому ваш поток будет спать в течение 30 секунд, и только тогда отправит ответ в браузер

Если вы хотите быстро вернуть ответ в свой браузер, вам нужно реализовать другую идею, которая заключается в том, чтобы начать новый поток, который отправляет электронное письмо, но не ждите он заканчивается, чтобы ваш поток продолжал работать и сразу же возвращал asnwer браузеру. Это известно как огонь и забыли. Чтобы понять, о чем я говорю, см. Это: Fire and forget approach. А затем внимательно прочитайте это: Fire and Forget (Asynch) ASP.NET Method Call. Учтите, что сам MVC имеет резьбу, и вам нужно учитывать это при использовании метода «огонь» и «забыть».

Obvioulsy в огне и забыть, контроллер не сможет обнаруживать ошибки во время отправки электронной почты, поскольку новый поток запускается сам по себе, пока основной поток уже завершен. Таким образом, вы должны реализовать что-то, чтобы хотя бы зарегистрировать возможную ошибку, и в идеале дать пользователю возможность узнать, что произошло (например, какие отчеты он может увидеть позже). Пожалуйста, ознакомьтесь с этим: ASP.NET Exception Handling in background threads