2009-07-19 13 views
2

Donc, voici le problème: Je construis des e-mails à envoyer par mon application en rendant les pages d'affichage complet aux chaînes et en les envoyant. Cela fonctionne sans problème tant que je ne redirige pas vers une autre URL sur le site par la suite. Chaque fois que j'essaie, je reçois "System.Web.HttpException: Impossible de rediriger après que les en-têtes HTTP ont été envoyés."Rendu de la vue à la chaîne suivie de la redirection des résultats en exception

Je crois que le problème vient du fait que je réutilise le contexte de l'action de contrôleur où l'appel pour créer le courrier vient. Plus spécifiquement, la réponse Http du contexte. Malheureusement, je ne peux pas créer une nouvelle HttpResponse qui utilise HttpWriter parce que le constructeur de cette classe est inaccessible, et l'utilisation de toute autre classe dérivée de TextWriter provoque une exception de réponse.Flush().

Quelqu'un at-il une solution pour cela?

public static string RenderViewToString(
     ControllerContext controllerContext, 
     string viewPath, 
     string masterPath, 
     ViewDataDictionary viewData, 
     TempDataDictionary tempData) 
    { 
     Stream filter = null; 
     ViewPage viewPage = new ViewPage(); 

     //Right, create our view 
     viewPage.ViewContext = new ViewContext(controllerContext, 
      new WebFormView(viewPath, masterPath), viewData, tempData); 

     //Get the response context, flush it and get the response filter. 
     var response = viewPage.ViewContext.HttpContext.Response; 
     //var response = new HttpResponseWrapper(new HttpResponse 
     // (**TextWriter Goes Here**)); 
     response.Flush(); 
     var oldFilter = response.Filter; 

     try 
     { 
      //Put a new filter into the response 
      filter = new MemoryStream(); 
      response.Filter = filter; 

      //Now render the view into the memorystream and flush the response 
      viewPage.ViewContext.View.Render(viewPage.ViewContext, 
       viewPage.ViewContext.HttpContext.Response.Output); 
      response.Flush(); 

      //Now read the rendered view. 
      filter.Position = 0; 
      var reader = new StreamReader(filter, response.ContentEncoding); 
      return reader.ReadToEnd(); 
     } 
     finally 
     { 
      //Clean up. 
      if (filter != null) 
       filter.Dispose(); 

      //Now replace the response filter 
      response.Filter = oldFilter; 
     } 
    } 

Répondre

2

Vous devrez initier une nouvelle requête. Bit, voulez-vous vraiment envoyer des emails de manière synchrone de cette façon? Si le serveur de messagerie est en panne, l'utilisateur peut attendre un bon moment.

Je mets toujours les courriels dans une file d'attente hors ligne et je les envoie par la poste. Vous pouvez envisager d'utiliser le moteur de modèle Spark pour cela.

Une autre approche est de ne pas rediriger mais écrire une page avec une balise meta redirection

+0

Je souhaite utiliser le moteur WebForms pour créer les corps de messagerie eux-mêmes. Spark est plutôt sympa, mais je suis toujours plus à l'aise avec l'idée d'utiliser WebForms. En passant, par nouvelle demande, je suppose HttpServerUtility.Execute est bon? En ce qui concerne l'envoi synchrone, il ne doit pas être de cette façon, tout dépend des paramètres de SmtpClient n'est-ce pas? Comme je peux l'envoyer dans un dossier pour l'envoyer plus tard, ce n'est pas un problème. –

0

Jetez un oeil à la MVC Contrib EmailTemplateService qui fait exactement ce que vous recherchez.

http://mvccontrib.googlecode.com/svn/trunk/src/MVCContrib/Services/EmailTemplateService.cs

Désolé Chris, pas tout à fait sûr de ce que je pensais mais je ne l'ai pas lu évidemment la question. Bien que je ne puisse pas vous donner un moyen de contourner cela, je peux vous dire pourquoi vous obtenez l'erreur - HttpResponse.Flush() envoie les en-têtes avant de vider le contenu de votre filtre. Cela définit un indicateur dans la réponse de sorte que lorsque vous essayez de rediriger vous obtenez l'exception. En utilisant le réflecteur pour regarder le code à l'intérieur de Flush, je ne vois aucun moyen propre de contourner ce problème sans beaucoup de réflexion et d'autres méchancetés.

+0

Non, cela aura le même problème. EmailTemplateService.RenderMessage() est pratiquement le même code que celui que j'utilise déjà, sauf faire un MailMessage au lieu d'une chaîne. –

+0

Je sais que c'est l'appel à Flush qui le provoque. Phil a raison, la seule façon de contourner cela est de créer une toute nouvelle requête. –

+0

DEAD LINK: Essayez ceci à la place! http: // github.com/mvccontrib/MvcContrib/blob/maître/src/MVCContrib/Services/EmailTemplateService.cs –

2

Voici une autre méthode pour rendre une vue d'une chaîne qui ne se traduit par des données étant sortie à la réponse (il doit donc éviter votre problème): http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/

Pour rendre une vue régulière au lieu d'une vue partielle , vous devrez changer "ViewEngines.Engines.FindPartialView" en "ViewEngines.Engines.FindView".