SmtpClient.SendMailAsync verursacht einen Deadlock beim Auslösen einer bestimmten Ausnahme

Ich versuche, eine E-Mail-Bestätigung für eine ASP.NET MVC5-Website basierend auf dem Beispiel AccountController aus der VS2013-Projektvorlage einzurichten. Ich habe das @ implementieIIdentityMessageService usingSmtpClient, versuche es so einfach wie möglich zu halten:

public class EmailService : IIdentityMessageService
{
    public async Task SendAsync(IdentityMessage message)
    {
        using(var client = new SmtpClient())
        {
            var mailMessage = new MailMessage("[email protected]", message.Destination, message.Subject, message.Body);
            await client.SendMailAsync(mailMessage);
        }
    }
}

Der aufrufende Controller-Code stammt direkt aus der Vorlage (in eine separate Aktion extrahiert, da ich andere mögliche Ursachen ausschließen wollte):

public async Task<ActionResult> TestAsyncEmail()
{
    Guid userId = User.Identity.GetUserId();

    string code = await UserManager.GenerateEmailConfirmationTokenAsync(userId);
    var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = userId, code = code }, protocol: Request.Url.Scheme);
    await UserManager.SendEmailAsync(userId, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");

    return View();
}

Jedoch bekomme ich seltsames Verhalten, wenn die E-Mail nicht gesendet werden kann, aber nur in einem bestimmten Fall, wenn der Host irgendwie nicht erreichbar ist. Beispielkonfiguration:

<system.net>
    <mailSettings>
        <smtp deliveryMethod="Network">
            <network host="unreachablehost" defaultCredentials="true" port="25" />
        </smtp>
    </mailSettings>
</system.net>

In diesem Fall scheint die Anforderung blockiert zu sein und gibt nichts an den Client zurück. Wenn die E-Mail aus einem anderen Grund nicht gesendet werden kann (z. B. wenn der Host die Verbindung aktiv ablehnt), wird die Ausnahme normal behandelt und ich erhalte eine YSOD.

Ein Blick auf die Windows-Ereignisprotokolle zeigt, dass einInvalidOperationException wird im selben Zeitraum mit der Meldung "Ein asynchrones Modul oder Handler wurde abgeschlossen, während eine asynchrone Operation noch ausstand." ausgelöst. Ich erhalte die gleiche Nachricht in einem YSOD, wenn ich versuche, das @ zu fangSmtpException in der Steuerung und geben ein @ zurüViewResult im catch-Block. Also finde ich dasawait -ed-Vorgang kann in beiden Fällen nicht abgeschlossen werden.

Soweit ich das beurteilen kann, befolge ich alle bewährten Methoden für die asynchrone / erwartete Übertragung, die in anderen Posts zu SO beschrieben sind (z. B. HttpClient.GetAsync (...) gibt bei Verwendung von await / async @ niemals zurü), hauptsächlich "async / wait ganz nach oben". Ich habe auch versucht mitConfigureAwait(false), ohne Änderung. Da der Code nur dann blockiert, wenn eine bestimmte Ausnahme ausgelöst wird, ist das allgemeine Muster in den meisten Fällen korrekt, aber intern geschieht etwas, das es in diesem Fall falsch macht. Aber da mir die gleichzeitige Programmierung ziemlich neu ist, habe ich das Gefühl, ich könnte mich irren.

Ist da etwas, was ich falsch mache? Ich kann immer einen synchronen Anruf verwenden (zBSmtpClient.Send()) in der SendAsync-Methode, aber es fühlt sich so an, als sollte dies so funktionieren, wie es ist.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage