2012-08-30 2 views
10

Ich benutze ASP.NET MVC 3 mit MVCMailer, ich habe versucht, E-Mails mit SendAsync zu senden, aber eigentlich dauert es noch länger.Senden asynchrone E-Mails

So brüllen Ich versuche Task.Factory wie der Code zu verwenden:

var task1 = Task.Factory.StartNew(
      state => 
      { 
       var mail = new UserMailer(); 
       var msg = mail.Welcome("My Name", "[email protected]"); 
       msg.SendAsync(); 
      }); 

    task1.Wait(); 

Das Problem ist, MVCMailer Httpcontext braucht, aber innerhalb dieser Aufgabe habe ich Httpcontext Null.

Wie kann ich Async-E-Mails senden?

Antwort

18

Eine kleine Ergänzung dazu. Hier ist eine Erweiterungsmethode, um einigen zu helfen.

using Mvc.Mailer; 
using System.Threading.Tasks; 
public static void SendEmailAsync(this MvcMailMessage msg, HttpContext currContext) 
{ 
     //make this process a little cleaner 
     Task.Factory.StartNew(() => 
     { 
      System.Web.HttpContext.Current = currContext; 
      msg.SendAsync(); 
     }); 
} 

Verwenden Sie es wie folgt aus Ihren Controller-Methoden.

Mailers.UserMailer um = new Mailers.UserMailer(); 
um.SendWelcomeEmail(dataObject).SendEmailAsync(ControllerContext.HttpContext.ApplicationInstance.Context); 
+0

Hey Matt! Danke für die Referenz, das sieht gut aus, sendet es asynchron 100%, ich habe gehört, dass Leute sagen, der MVCMailer sei Pseudoasync haha. Danke Kumpel! – Baconbeastnz

+2

Kein Problem! Ich schlug meinen Kopf gegen den Schreibtisch für ein bisschen mit diesem :) – Matt

+0

@ Matt, es funktioniert super !!! Danke!!! =) –

0

Sie brauchen keine Aufgaben. SendAsync ist asynchron und verwendet einen anderen Thread self. Aufgaben beschleunigen nicht Ihr Mailen.

UPDATE: Wenn ich das gleiche Problem lösen, verwende ich Task und synchrone senden. Es scheint, dass SendAsync nicht so asynchron war. Es ist Probe von meinem Code (es ist nicht Httpcontext ist wollen):

public void SendMailCollection(IEnumerable<Tuple<string, string, MailAddress>> mailParams) 
    { 
     var smtpClient = new SmtpClient 
     { 
      Credentials = new NetworkCredential(_configurationService.SmtpUser, _configurationService.SmtpPassword), 
      Host = _configurationService.SmtpHost, 
      Port = _configurationService.SmtpPort.Value 
     }; 

     var task = new Task(() => 
           { 
            foreach (MailMessage message in mailParams.Select(FormMessage)) 
            { 
             smtpClient.Send(message); 
            } 

           }); 
     task.Start(); 
    } 

    private MailMessage FormMessage(Tuple<string, string, MailAddress> firstMail) 
    { 
     var message = new MailMessage 
      { 
       From = new MailAddress(_configurationService.SmtpSenderEmail, _configurationService.SmtpSenderName), 
       Subject = firstMail.Item1, 
       Body = firstMail.Item2 
      }; 
     message.To.Add(firstMail.Item3); 
     return message; 
    } 
+0

Kirill, warum dauert es länger? Ich muss E-Mail im Hintergrund senden. –

+0

Asynchron ist nicht schnell. Das bedeutet, dass Ihr langsamer Prozess Ihren Basis-Thread nicht blockiert und Ihre Anwendung auf Benutzeraktionen reagiert. –

+0

Sicher, aber wenn ich E-Mails sende, wird der Prozess von dieser Aufgabe blockiert. –

4

Task.Factory.StartNew wird einen neuen Thread erstellen.
Wenn Sie Httpcontext zuzugreifen, die in dem Haupt-Thread ist, dass Sie haben, dies zu tun:

var task1 = Task.Factory.StartNew(() => 
    { 
    System.Web.HttpContext.Current = ControllerContext.HttpContext.ApplicationInstance.Context; 
    var mail = new UserMailer(); 
    var msg = mail.Welcome("My Name", "[email protected]"); 
    msg.SendAsync(); 
    }); 

task1.Wait(); 

Es gibt eine lange Debatte, ob es besser ist, TPL oder QueueUserWorkItem zu verwenden.
Jemand hat versucht, die issue zu adressieren.
Dies ist die QueueUserWorkItem Version:

public class HomeController : Controller 
{ 
    private AutoResetEvent s_reset = new AutoResetEvent(false); 

    public ActionResult Index() 
    { 
     var state = new WorkerState() { HttpContextReference = System.Web.HttpContext.Current }; 
     ThreadPool.QueueUserWorkItem(new WaitCallback(EmaiSenderWorker), state); 

     try 
     { 
     s_reset.WaitOne(); 
     } 
     finally 
     { 
     s_reset.Close(); 
     } 

     return View(); 
    } 

    void EmaiSenderWorker(object state) 
    { 
     var mystate = state as WorkerState; 

     if (mystate != null && mystate.HttpContextReference != null) 
     { 
     System.Web.HttpContext.Current = mystate.HttpContextReference; 
     } 

     var mail = new UserMailer(); 
     var msg = mail.Welcome(); 
     msg.SendAsync(); 

     s_reset.Set(); 
    } 

    private class WorkerState 
    { 
     public HttpContext HttpContextReference { get; set; } 
    } 

} 
+0

Ja LeflyX! Ich habe das bereits versucht, aber ich weiß nicht, ob es möglich ist, die Kontextvariable an das MVCMailer-Objekt zu übergeben. –

+1

@MichelAndrade: Ich habe meine Antwort aktualisiert. Versuchen Sie zu sehen, ob es hilft. – LeftyX

+0

LeflyX, Fast da, wenn ich "task1.Wait();" es funktioniert nicht –

0
public class UserMailer : MailerBase  
{ 
    RegisterService Service = new RegisterService(); 
    HttpContext Context; 
    public UserMailer(HttpContext context) 
    { 
     Context = context; 
     MasterName="_Layout"; 
    } 

    public void ConfirmRegistration(Register model) 
    { 
     SendAsync(() => 
     { 
      model.Conference = Service.Context.Conferences.Find(model.ConferenceID); // load conference bcs it fails to lazy load automatically. 
      ViewData.Model = model; 
      return Populate(x => 
      { 
       x.Subject = "You registered for " + model.Conference.Name + "!"; ; 
       x.ViewName = "Confirm"; 
       x.To.Add(model.Email); 
      }); 
     }); 
    } 

    private void SendAsync(Func<MvcMailMessage> GetEmail) 
    { 
     Task.Factory.StartNew(() => 
     { 
      System.Web.HttpContext.Current = Context; 
      GetEmail().Send(); 
     }); 
    } 
+2

Danke für das Posten einer Antwort! Während ein Code-Snippet die Frage beantworten kann, ist es immer noch großartig, zusätzliche Informationen hinzuzufügen, wie zum Beispiel erklären, etc .. – j0k