2009-08-15 3 views
4

Je ne peux pas rendre une vue à une chaîne, puis rediriger, malgré this answer from Feb (après la version 1.0, je pense) qui prétend que c'est possible. Je pensais que je faisais quelque chose de mal, et puis j'ai lu ce answer from Haack in July qui prétend que ce n'est pas possible.Rendu d'une vue à une chaîne dans MVC, puis redirection - solutions de contournement?

Si quelqu'un l'a fait fonctionner et peut m'aider à le faire fonctionner, c'est génial (et je posterai du code, des erreurs). Cependant, je suis sur le point d'avoir besoin de solutions de contournement. Il y en a quelques-uns, mais rien d'idéal. Quelqu'un a-t-il résolu cela ou a-t-il des commentaires sur mes idées?

  1. Ceci est de rendre le courrier électronique. Bien que je puisse sûrement envoyer l'email en dehors de la requête web (stocker des informations dans un db et l'obtenir plus tard), il y a beaucoup de types de mails et je ne veux pas stocker les données du template (objet utilisateur, quelques autres objets LINQ) dans un db pour le laisser être rendu plus tard. Je pourrais créer un POCO plus simple et sérialisable et le sauvegarder dans le db, mais pourquoi? ... Je veux juste du texte rendu!
  2. Je peux créer un nouvel objet RedirectToAction qui vérifie si les en-têtes ont été envoyés (ne peut pas comprendre comment faire cela - try/catch?) Et, si c'est le cas, construit une page simple avec une méta-redirection, une redirection JavaScript, ainsi qu'un lien "cliquez ici".
  3. Dans mon contrôleur, je peux me rappeler si j'ai rendu un email et, si c'est le cas, manuellement # 2 en affichant une vue.
  4. Je peux envoyer manuellement les en-têtes de redirection avant tout rendu de courrier électronique potentiel. Ensuite, plutôt que d'utiliser l'infrastructure MVC pour rediriger vers l'action, j'appelle simplement result.end. Cela semble plus facile, mais vraiment salissant.
  5. Autre chose?

EDIT: J'ai essayé le code de Dan (très similaire au code de Jan/Feb que je l'ai déjà essayé) et je me fais toujours la même erreur. La seule différence substantielle que je peux voir est que son exemple utilise une vue pendant que j'utilise une vue partielle. Je vais essayer de tester cela plus tard avec une vue.

Voici ce que j'ai:

Contrôleur

public ActionResult Certifications(string email_intro) 
     { 
      //a lot of stuff 

      ViewData["users"] = users; 

      if (isPost()) 
      { 
       //create the viewmodel 
       var view_model = new ViewModels.Emails.Certifications.Open(userContext) 
       { 
        emailIntro = email_intro 
       }; 

       //i've tried stopping this after just one iteration, in case the problem is due to calling it multiple times 
       foreach (var user in users) 
       { 
        if (user.Email_Address.IsValidEmailAddress()) 
        { 
         //add more stuff to the view model specific to this user 
         view_model.user = user; 
         view_model.certification302Summary.subProcessesOwner = new SubProcess_Certifications(RecordUpdating.Role.Owner, null, null, user.User_ID, repository); 
         //more here.... 

         //if i comment out the next line, everything works ok 
         SendEmail(view_model, this.ControllerContext); 
        } 
       } 

       return RedirectToAction("Certifications"); 
      } 

      return View(); 
     } 

SendEmail()

public static void SendEmail(ViewModels.Emails.Certifications.Open model, ControllerContext context) 
     { 
      var vd = context.Controller.ViewData; 
      vd["model"] = model; 
      var renderer = new CustomRenderers(); 
      //i fixed an error in your code here 
      var text = renderer.RenderViewToString3(context, "~/Views/Emails/Certifications/Open.ascx", "", vd, null); 
      var a = text; 
     } 

CustomRenderers

public class CustomRenderers 
    { 
     public virtual string RenderViewToString3(ControllerContext controllerContext, string viewPath, string masterPath, ViewDataDictionary viewData, TempDataDictionary tempData) 
     { 
      //copy/paste of dan's code 
     } 
    } 

Erreur

[HttpException (0x80004005): Cannot redirect after HTTP headers have been sent.] 
    System.Web.HttpResponse.Redirect(String url, Boolean endResponse) +8707691 

Merci, James

+0

Avez-vous déjà trouvé ce produit? – Kirschstein

Répondre

0
public Action SendEmail(int id) 
{ 
    //Let's say that id is the db id of an order that a customer has just placed. 

    //Go get that model from the db. 
    MyModel model = new Model(id); 

    //Now send that email. Don't forget the model and controller context. 
    SendEmail(model, this.ControllerContext); 

    //Render (or redirect!) 
    return RedirectToAction("Wherever"); 
} 

private static void SendEmail(MyModel model, ControllerContext controllerContext) 
{ 
    //Recreate the viewdata 
    ViewDataDictionary viewData = controllerContext.Controller.ViewData; 
    viewData["Order"] = model; 
    string renderedView = ""; 
    CustomRenderers customRenderers = new CustomRenderers(); 

    //Now render the view to string 
    //ControllerContext, ViewPath, MasterPath, ViewDataDictionary, TempDataDictionary 
    //As you can see, we're not passing a master page, and the tempdata is in this instance. 
    renderedView = RenderViewToString(controllerContext, "~/Views/Orders/Email.aspx", "", viewData, null); 

    //Now send your email with the string as the body. 
    //Not writing that, as the purpose is just to show the rendering. :) 
} 


//Elsewhere... 
public class CustomRenderers 
{ 
    public virtual string RenderViewToString(ControllerContext controllerContext, string viewPath, string masterPath, ViewDataDictionary viewData, TempDataDictionary tempData) 
    { 
    if (tempData == null) 
    { 
    tempData = new TempDataDictionary(); 
    } 

    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; 
    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; 
    } 
    } 
} 

vos commandes/vue Email.aspx, assurez-vous que vous faites référence à tout le ViewData, plutôt que le modèle.vous pouvez le faire:

<% MyModel model = (MyModel)ViewData["Order"] %> 
+0

Dan - Merci d'avoir essayé, mais je reçois la même erreur "ne peut pas rediriger" que je recevais après avoir utilisé le code de votre publication de janvier. J'ai tout collé dans ma question. Qu'est-ce que je fais mal? Merci. –

0

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 (donc il faut éviter que 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".

0

Mis à jour.

Maintenant que je comprends que vous voulez utiliser le moteur de vue de générer l'e-mail réelle en html, je propose ce qui suit:

Code pour rendre l'action au texte d'un contrôleur: http://mikehadlow.blogspot.com/2008/06/mvc-framework-capturing-output-of-view_05.html

Modifications mineures à votre code:

public ActionResult Certifications(string email_intro) 
{ 
    //a lot of stuff    
    ViewData["users"] = users;    
    if (isPost())    
    {     
     //create the viewmodel     
     var view_model = new ViewModels.Emails.Certifications.Open(userContext) { emailIntro = email_intro };     

     foreach (var user in users)     
     {      
      if (user.Email_Address.IsValidEmailAddress())      
      {       
       view_model.user = user;       
       view_model.certification302Summary.subProcessesOwner = new SubProcess_Certifications(RecordUpdating.Role.Owner, null, null, user.User_ID, repository);       

       SendEmail(view_model);      
      }     
     }     
     return RedirectToAction("Certifications");    
    }    
    return View();   
} 

public void SendEmail(ViewModels.Emails.Certifications.Open model)   
{    
    var vd = context.Controller.ViewData;    
    vd["model"] = model;    
    var renderer = new CustomRenderers();    

    // Implement the actual email rendering as a regular action method on this controller 
    var text = this.CaptureActionHtml(c => (ViewResult)c.RenderEmail(model)); 

    var a = text;   
} 
+0

Comment suggérez-vous que je réalise ce que j'ai essayé de faire dans l'exemple? c'est-à-dire que je veux utiliser le moteur de création de modèles pour créer des emails plutôt que de les concaténer ensemble et un tas de HTML ensemble. –

+0

Merci ... Je vais y jeter un coup d'œil quand je reviendrai sur ce projet dans un mois ou deux. –

Questions connexes