2016-10-07 3 views
-1

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.

+3

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. –

+1

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

+0

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 –

Antwort

0

Nachdem Sie die Site in einem neuen Projekt dupliziert und alle Abhängigkeiten von Nuget installiert haben, haben wir sie schließlich an den Proxy-Server angehängt, auf dem Cisco IronPort läuft.

Möglicherweise aufgrund einer Fehlkonfiguration oder etwas, das das Infrastrukturteam absichtlich eingerichtet hat, sendet der Proxyserver zwei identische Anforderungen an den Server, obwohl nur einer vom Client gesendet wird.

Die Deaktivierung des Proxyservers oder der Besuch von einer externen (Telefon-) Verbindung führt zu einer Anforderung.