2011-03-10 4 views
17

Mi piacerebbe utilizzare le funzionalità di Binding/Rendering modello di una Razor View per generare il contenuto del corpo HTML per un'e-mail che sto inviando dalla mia applicazione ASP.NET MVC.Posso utilizzare una vista Razor MVC ASP.Net per generare un corpo HTML ben formattato come input per un messaggio di posta elettronica inviato dal server?

C'è un modo per rendere una vista a una stringa invece di restituirla come ActionResult di una richiesta GET?

Per illustrare Sto cercando qualcosa che farà il seguente ...

public ActionResult SendEmail(int id) 
    { 
     EmailDetailsViewModel emailDetails = EmailDetailsViewModel().CreateEmailDetails(id); 

     // THIS IS WHERE I NEED HELP... 
     // I want to pass my ViewModel (emailDetails) to my View (EmailBodyRazorView) but instead of Rending that to the Response stream I want to capture the output and pass it to an email client. 
     string htmlEmailBody = View("EmailBodyRazorView", emailDetails).ToString(); 

     // Once I have the htmlEmail body I'm good to go. I've got a utilityt that will send the email for me. 
     MyEmailUtility.SmtpSendEmail("[email protected]", "Email Subject", htmlEmailBody); 

     // Redirect another Action that will return a page to the user confirming the email was sent. 
     return RedirectToAction("ConfirmationEmailWasSent"); 
    } 
+1

possibile duplicato di [come visualizzare un rasoio, ottenere l'html di una vista renderizzata all'interno di un'azione] (http://stackoverflow.com/questions/4692131/how-to-render-a-razor-view-get -the-html-of-a-render-view-inside-an-action) – marcind

+0

@marcind sei corretto. Grazie. c'è un modo per me per contrassegnare questo come un duplicato? – Justin

+0

ottima domanda! – toddmo

risposta

26

Se avete solo bisogno di rendere la vista in una stringa provare qualcosa di simile:

public string ToHtml(string viewToRender, ViewDataDictionary viewData, ControllerContext controllerContext) 
{ 
    var result = ViewEngines.Engines.FindView(controllerContext, viewToRender, null); 

    StringWriter output; 
    using (output = new StringWriter()) 
    { 
     var viewContext = new ViewContext(controllerContext, result.View, viewData, controllerContext.Controller.TempData, output); 
     result.View.Render(viewContext, output); 
     result.ViewEngine.ReleaseView(controllerContext, result.View); 
    } 

    return output.ToString(); 
} 

sarà necessario passare il nome della vista e il Viewdata e ControllerContext dall'azione del controller.

+0

Molto simile a questa soluzione http://stackoverflow.com/questions/4692131/how-to-render-a-razor-view-get-the-html-of-a-rendered-view-inside-an-action as menzionato da @marcind. Ma ti darò la risposta dato che non so come contrassegnare questo come un duplicato :) Grazie a questo è l'approccio generale che ho finito per usare. – Justin

+1

Thx - guardando indietro Vedo che mi manca un blocco using() su StringWriter IDisposable.Spero che te lo ricordi sulla tua parte. –

+1

È possibile modificare il codice di esempio –

10

Si può checkout Postal per l'utilizzo di viste per l'invio di messaggi di posta elettronica.

+0

Un progetto accurato ti ha dato un punto, ma ho già ricevuto l'email che inviava una parte collegata al mio back-end, quindi la semplice soluzione View.Render è un po 'più leggera per i miei scopi. Grazie comunque! – Justin

3

Un altro si sarebbe ActionMailer.Net: https://bitbucket.org/swaj/actionmailer.net/wiki/Home

Dal sito web: Una porta MVC 3 a base della biblioteca Rails ActionMailer ad ASP.NET MVC. L'obiettivo è rendere semplice e relativamente indolore inviare e-mail dalla tua applicazione.

NuGet: Install-Package ActionMailer

1

C'è anche il pacchetto Essential Mail: Razor da NuGet. È costruito su RazorEngine e fornisce un'interfaccia semplice per il rendering delle e-mail. modello di messaggio

-mail simile a

@inherits Essential.Templating.Razor.Email.EmailTemplate 
@using System.Net; 
@{ 
    From = new MailAddress("[email protected]"); 
    Subject = "Email Subject"; 
} 
@section Html 
{ 
    <html> 
     <head> 
      <title>Example</title> 
     </head> 
     <body> 
      <h1>HTML part of the email</h1> 
     </body> 
    </html> 
} 
@section Text 
{ 
    Text part of the email. 
} 

Il progetto è ospitato su GitHub: https://github.com/smolyakoff/essential-templating/wiki/Email-Template-with-Razor

0

Sulla base di risposta di Ryan, ho fatto un metodo di estensione:

public static string RenderViewToString(this Controller source, string viewName) 
{ 
    var viewEngineResult = ViewEngines.Engines.FindView(source.ControllerContext, viewName, null); 
    using (StringWriter output = new StringWriter()) 
    { 
    viewEngineResult.View.Render(new ViewContext(source.ControllerContext, viewEngineResult.View, source.ViewData, source.TempData, output), output); 
    viewEngineResult.ViewEngine.ReleaseView(source.ControllerContext, viewEngineResult.View); 
    return output.ToString(); 
    } 
} 

Per chiamare da all'interno di un'azione del controllore (esempio di utilizzo):

[AllowAnonymous] 
    public class ErrorController : Controller 
    { 
    // GET: Error 
    public ActionResult Index(System.Net.HttpStatusCode id) 
    { 
     Exception ex = null; // how do i get the exception that was thrown? 
     if (!Debugger.IsAttached) 
     Code.Email.Send(ConfigurationManager.AppSettings["BugReportEmailAddress"], 
      $"Bug Report: AgentPortal: {ex?.Message}", 
      this.RenderViewToString("BugReport")); 
     Response.StatusCode = (int)id; 
     return View(); 
    } 
    }