C# Асинхронни задачи - MANDRILL API

Настройвам Mandrill API за нашите вътрешни системи.

Мога да накарам API да работи добре и мога да получавам имейлите от него, проблемът, който имам, е, че когато се опитам да получа резултата от заявката за изпращане, системата просто виси за неопределено време.

Моят код е както следва:

public async Task<bool> SendEmail(MandrillSendTemplateRequest request)
{
    var result = await _mandrill.SendMessageTemplate(Map(request));
    return result[0].Status.ToString() == "sent";
}

Ако стартирам горния код БЕЗ връщане, тогава имейлът се изпраща добре. Ако стартирам горния код С връщането, тогава имейлът се изпраща добре, но програмата ми просто увисва.

Може ли някой да хвърли светлина върху този въпрос?

Редактиране. За справка използвам Mandrill .Net Wrapper от Shawn Mclean от NuGet Packages. Mandrill API 2.2.7

Редактиране. Събитие за щракване върху бутон, което извиква метода SendEmail:

  Private Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click

    Try
        WaitCursor = True

        Dim mgr As New CustomerCommunicationsManager()
        Dim r As New MandrillSendTemplateRequest()
        Dim m As New MandrillMessage()

        m.FromEmail = "[email protected]"
        m.FromName = "fromName"

        m.Subject = "Test"
        m.ForeName = "Software"
        m.Surname = "Dept"
        m.EmailAddress = "[email protected]"

        r.Message = m
        r.TemplateName = "WelcomeBasic"

        Dim sent As Boolean = mgr.Mandrill.SendEmail(r).Result

    Catch ex As Exception

    Finally
        WaitCursor = False
    End Try


End Sub

Редактиране. Код за Map(request) (метод SendEmail)

private SendMessageTemplateRequest Map(MandrillSendTemplateRequest obj)
{
    if (obj == null) { return null; }
    return new SendMessageTemplateRequest(Map(obj.Message), obj.TemplateName, Map(obj.TemplateContent));
}

private EmailMessage Map(MandrillMessage obj)
{
    if (obj == null) { return null; }

    return new EmailMessage
    {
        AutoHtml = obj.AutoHtml,
        AutoText = obj.AutoText,
        FromEmail = obj.FromEmail,
        FromName = obj.FromName,
        Important = obj.Important,
        PreserveRecipients = obj.PreserveRecipients,
        Subject = obj.Subject,
        Tags = obj.tags,
        To = new EmailAddress[] { new EmailAddress(obj.EmailAddress, obj.FullName) },
        TrackOpens = obj.TrackOpens,
        TrackClicks = obj.TrackClicks
    };
}

private IEnumerable<TemplateContent> Map(IEnumerable<MandrillTemplateContent> obj)
{
    if (obj == null) { return null; }

    List<TemplateContent> content = new List<TemplateContent>();

    foreach (MandrillTemplateContent c in obj)
    {
        content.Add(new TemplateContent{ Content = c.Content, Name = c.Name });
    }

    return content;
}

person Richard.Gale    schedule 16.11.2015    source източник
comment
Трябва също да публикувате как извиквате този метод. Извиквате ли Wait или Result при върнатата задача?   -  person Daniel Kelley    schedule 16.11.2015
comment
Просто извиквам както по-горе, частта _mandrill всъщност е препратката към техния API.   -  person Richard.Gale    schedule 16.11.2015
comment
И така, как се нарича SendMail? Какво нарича това?   -  person Daniel Kelley    schedule 16.11.2015
comment
В момента, тъй като просто тествам, идва от събитие за щракване върху бутон на Windows Form   -  person Richard.Gale    schedule 16.11.2015
comment
Или индексаторът на result, инструментът за получаване на Status или методът ToString() виси. Отстранявали ли сте грешки с помощта на step into? опитайте да поставите точки на прекъсване в индексатора/аксесора/tostring   -  person Philippe Paré    schedule 16.11.2015
comment
ако поставя точка на прекъсване при връщане, тогава точката на прекъсване не се достига. ако точката на прекъсване е на тригера (var result = await...), тогава не се вижда грешка.   -  person Richard.Gale    schedule 16.11.2015
comment
Покажете кода, който извиква SendEmail   -  person i3arnon    schedule 16.11.2015
comment
Редактирах оригиналния пост. Моля, вижте по-горе. Благодаря.   -  person Richard.Gale    schedule 16.11.2015


Отговори (1)


Имате задънена улица, защото блокирате асинхронен метод в контекста на нишката на потребителския интерфейс. Не трябва да блокирате асинхронен код, трябва да го изчакате:

Private Async Sub btnTest_Click(sender As Object, e As EventArgs) Handles btnTest.Click
...
        Dim sent As Boolean = Await mgr.Mandrill.SendEmail(r)
End Sub

Нишката на потребителския интерфейс има SynchronizationContext (можете да видите това SynchronizationContext.Current != null), който гарантира, че кодът след изчакване се публикува в единичната нишка на потребителския интерфейс.

Тъй като блокирате UI нишката с Task.Result, кодът след await не може да се изпълни, което означава, че задачата не може да завърши и така UI нишката ще блокира завинаги.

Можете да смекчите това, като кажете на await да не улавя SynchronizationContext с помощта на ConfigureAwait(false), но въпреки че това е добра практика, не трябва да блокирате като начало:

public async Task<bool> SendEmailAsync(MandrillSendTemplateRequest request)
{
    var result = await _mandrill.SendMessageTemplate(Map(request)).ConfigureAwait(false);
    return result[0].Status.ToString() == "sent";
}
person i3arnon    schedule 16.11.2015
comment
Здравейте, много ви благодаря за отговора, сега имам проблем с компилирането, тъй като изразът е от тип „Boolean“, което не се чака. - person Richard.Gale; 17.11.2015
comment
@Richard.Gale Изглежда, че се опитвате да изчакате нещо, което не връща задача. Сигурни ли сте, че извиквате асинхронен метод? - person i3arnon; 17.11.2015
comment
Да, това е, което прочетох онлайн, че всички обаждания в този API са асинхронни - person Richard.Gale; 17.11.2015
comment
@Richard.Gale Ако методът не връща задача, той не е част от модела async-await. - person i3arnon; 17.11.2015
comment
Как да разбера дали връща задача? - person Richard.Gale; 17.11.2015
comment
@Richard.Gale можете да използвате Go To Declaration във Visual Studio - person i3arnon; 17.11.2015
comment
връща Task‹List‹EmailResult›› - person Mike W; 16.02.2017