Ich habe begrenzte Erfahrung mit .NET async Aufgaben, aber ich habe HintergrundWorker und IAsyncResult in der Vergangenheit verwendet. Der folgende Code befindet sich in einem MVC4-Projekt. Wenn es keine Fehler gibt, funktioniert alles gut. Das Problem ist, wenn etwas fehlschlägt. Es scheint etwas Unerwartetes mit dem asynchronen Anruf zu geschehen, den ich nicht erklären kann.Unerklärlichen Fluss mit MVC async
Momentan sind die SMTP-Servereinstellungen auf einen nicht vorhandenen Server festgelegt, so dass der Code beim asynchronen Aufruf an await smtp.SendMailAsync(message);
ausgebombert wird. Anstatt dass der Aufruf an den Mail-Server einen Fehler generiert, scheint der Fehler von irgendwo im Benutzererstellungsprozess "Der Name ist bereits vergeben" zu kommen. Dies ist definitiv nicht der Fall, da jeder zufällig eingegebene Benutzername die Nachricht verursacht (zB: "[email protected]").
Was ich erwarten würde:
- Der Benutzer erstellt wird
- Rollen werden
- Der Anruf hinzugefügt versagt die E-Mail zu senden, Erzeugen einer 'Connection refused Server Mail' Fehler.
Was passiert eigentlich:
- Der Benutzer erstellt wird
- Rollen hinzugefügt
- Der Aufruf der E-Mail senden fehlschlägt, aber die Fehlermeldung kommt von irgendwo in .NET des Benutzers Erzeugungslogik in IUserStore.
Ich bekomme das erwartete Ergebnis lokal, aber auf dem Server bekomme ich das bizarre Verhalten.
Der Benutzer Methode erstellen scheinbar um den Fehler verursachen:
public virtual Task CreateAsync(User user)
{
if (user == null)
throw new ArgumentNullException("user");
return Task.Factory.StartNew(() =>
{
using (SqlConnection cn = new SqlConnection(DbHelper.ConnectionString))
{
cn.Insert<User>(user);
}
});
}
Die Aktion im Registrierungscontroller:
[POST("register")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel vm)
{
if (ModelState.IsValid)
{
var user = AutoMapper.Mapper.Map<User>(vm);
user.PasswordDate = DateTime.Now;
var result = await _userManager.CreateAsync(user); // Error message seems to come from here
if (result.Succeeded)
{
// Add roles
//...
foreach (var area in vm.AllowedAreas.Where(a => a.Value))
await _userManager.AddClaimAsync(user.Id, new Claim("Area", area.Key));
// Generate an email and send it out
var thanksForRegisteringVm = new ThanksForRegisteringViewModel();
thanksForRegisteringVm.FullName = vm.FullName;
thanksForRegisteringVm.EmailAddress = vm.EmailAddress;
var emailBody = RenderViewAsString.Render("~/Views/Emails/ThanksForRegistering.cshtml", thanksForRegisteringVm);
var message = new MailMessage()
{
Subject = "Thanks for Registering",
Body = emailBody,
IsBodyHtml = true
};
message.To.Add(vm.EmailAddress);
var smtp = new SmtpClient();
await smtp.SendMailAsync(message); // this will definitely be the true source of the error - a non existant mail server in web.config
return RedirectToAction("ThanksForRegistering");
}
else
{
foreach (var error in result.Errors)
ModelState.AddModelError("", error);
}
}
// If we got this far, something failed, redisplay form
setUpRegisterViewModel(vm);
return View(vm);
}
Update: Wir haben dies in der auf eine Differenz irgendwo verengt IIS-Konfiguration zwischen lokal, dev und live. Lokale und Entwickler arbeiten, leben nicht. Dinge, die wir haben eliminiert:
- App Pool (erstellt ein neues Geschäft)
- Elmah (von Live entfernt)
- applicationhost.config
Die Aktion Methode wird zweimal aufgerufen zu werden, und zwar unabhängig des Controllers für GET- und POST-Anfragen, aber nur, wenn eine Ausnahme ausgelöst wird. Es ist, als würde die erste Ausnahme die Aktionsmethode erneut ausführen.
Sind Sie sicher, dass hier nicht etwas anderes vor sich geht, das Ihr Debugging verschleiert - z. Die Anforderungspipeline wird zweimal ausgelöst und versucht daher, den Benutzer zweimal zu erstellen. Logisch ist nichts falsch mit diesem Code, also muss es ein Umweltproblem irgendeiner Art sein. –
Das ist so seltsam - die Einstellungen sind die gleichen, soweit ich sehen kann. Auf dem Produktionsserver läuft nichts Ungewöhnliches, was mich dazu bringt, mein Verständnis von Tasks und Async in Frage zu stellen. – Echilon
Alles, was dazu führt, dass der Browser die Anfrage zweimal sendet - ich kann nur vorschlagen, dass Sie die Anforderungsprotokollierung implementieren und von dort rückwärts arbeiten. Ich denke nicht, dass SO Ihnen mit diesem –