4

Hi I'm having a bit of a nightmare here!

I'mv trying output a webform to html using page.rendercontrol and htmltextwriter but it is resulting in a blank email.

Code:

   StringBuilder sb = new StringBuilder();
   StringWriter sw = new StringWriter(sb);
   HtmlTextWriter htmlTW = new HtmlTextWriter(sw);

   page.RenderControl(htmlTW);

   String content = sb.ToString();

   MailMessage mail = new MailMessage();

   mail.From = new MailAddress("test@test.com");
   mail.To.Add("steve@test.com");
   mail.IsBodyHtml = true;

   mail.Subject = "Test";
   mail.Body = content;

    SmtpClient smtp = new SmtpClient("1111");
    smtp.Send(mail);

    Response.Write("Message Sent");

I also tried it by rendering a single textbox and got and error saying It needed to be within form tags (which are on the masterpage).

I tried this fix: http://forums.asp.net/p/1016960/1368933.aspx#1368933 and added:

public override void 

VerifyRenderingInServerForm(Control control) { return; }

But now the errror I get is:

VerifyRenderingInServerForm(Control)': no suitable method found to override

Does anyone have a fix for this? I'm tearing my hair out!!

Thanks,

Steve

Steve McCall
  • 363
  • 3
  • 6
  • 12
  • What part of the page life-cycle are you calling that code in? I assume that the lower case `page` is a typo as the `Page` property should have an uppercase "P", and debugging through a page with that in Page_Load fills the string builder with the full HTML, but then the page throws an error about having multiple form elements as I'm not doing anything with the output. – Zhaph - Ben Duguid Mar 22 '10 at 09:06

5 Answers5

4

This is what I do, in vb:

Dim sw as New StringWriter()
Dim writer as New HtmlTextWriter(sw)
System.Web.HttpContext.Current.Server.Execute("YourPage.aspx", writer)
Dim message as String = sw.ToString()
Barry
  • 2,053
  • 3
  • 17
  • 28
  • Thanks for your help. I tried this method but couldn't get it to work. It would just get in a loop and output the same text over and over again. I don't think I implemented it correctly though – Steve McCall Mar 21 '10 at 07:46
  • This isn't called from the page I'm trying to render, but from somewhere else in the code, usually in a business layer. – Barry Mar 22 '10 at 12:21
  • I need to set 2 fields on the page before it gets rendered, is there a way to do it like this? – Thiago Dantas Dec 20 '12 at 19:36
  • I haven't tried it but I'd assume you can add them as parameters and use a query string to pass them in. – Barry Dec 27 '12 at 18:05
  • in C# `var sw = new StringWriter(); var writer = new HtmlTextWriter(sw); System.Web.HttpContext.Current.Server.Execute("YourPage.aspx", writer); string message = sw.ToString();` – JP Hellemons Jun 06 '16 at 12:21
1

If you don't need to redirect the page, after you render the contents of the page (from your code sample, it doesn't look like you need to), then you may want to use a Response.Filter.

Off the top of my head, it would look something like:

protected void Page_Load(object sender, System.EventArgs e) 
{
   Response.Filter = new SmtpFilter(Response.Filter);
}

The SmtpFilter class, is just a class that inherits from the Stream object.

The main method will be the Write method. Here is some code off the top of my head to Override the Write(...) method, send the Smtp mail, and continue on processing.

    public override void Write(byte[] buffer, int offset, int count) {
    // get the html
    string content= System.Text.Encoding.UTF8.GetString(buffer, offset, count);

   MailMessage mail = new MailMessage();  

   mail.From = new MailAddress("test@test.com");  
   mail.To.Add("steve@test.com");  
   mail.IsBodyHtml = true;  

   mail.Subject = "Test";  
   mail.Body = content;  

    SmtpClient smtp = new SmtpClient("1111");  
    smtp.Send(mail);  


    buffer = System.Text.Encoding.UTF8.GetBytes(HTML);
    this.Base.Write(buffer, 0, buffer.Length);    
    }

If you need more help on Response.Filters, you may want to google it. The first article I found was in VB.NET, but still helpful:

http://aspnetlibrary.com/articledetails.aspx?article=Use-Response.Filter-to-intercept-your-HTML

dave wanta
  • 7,164
  • 3
  • 29
  • 29
  • Hi, thanks a lot for this answer. It looks like what I need. Will it output the values entered by the user filling in the form? I'll try this out on Monday and let you know how I get on. – Steve McCall Mar 21 '10 at 07:45
  • If the form has been posted back, then yes. This is one of the lasts steps in the Response pipeline, so you will get what is being sent to the browser (javascript and all -- so, you will need to be sure to remove any script from your email). – dave wanta Mar 21 '10 at 19:58
  • Ok, I've tried this and get a error stating that the smtpfilter doesn't exist. Also that there is no definition for 'Base' Any ideas? – Steve McCall Mar 23 '10 at 13:28
  • You have to create your own SmtpFilter class. Check out the article I linked too. They called their class "ReplaceHTML". It inherits from the Stream class. – dave wanta Mar 24 '10 at 03:38
1

So I was struggling with this and FINALLY found the answer...

I was trying to extract the rendered HTML of a GridView and place it in an email. Everything worked perfectly when that action was happening on a Page, but when I moved the functionality into a User Control, the VerifyRenderingInServerForm method no longer works because it is a Page method, not a Control method.

To fix this, you have to override the Render method and call up to the Page to insure that control is rendered in a form with a runat=server tag. Here is the fix...

protected override void Render(HtmlTextWriter writer)
{
    if (Page != null)
    {
        Page.VerifyRenderingInServerForm(this);
    }
    base.Render(writer);
}

Thats HOURS of wasted time right there, but finally!

Vikdor
  • 23,934
  • 10
  • 61
  • 84
  • Okay, I spoke too soon. My session got dumped and the issue was actually still occurring. But I have now ACTUALLY fixed it. I just placed the VerifyRenderingInServerForm method in the page that my control was placed in. Kill the method perminantly; don't know why I didn't think of that earlier. – Mark Norman Jan 29 '11 at 00:37
0

This is the method I use to cram my webforms into an email:

private string HtmlPageInToString()
{
WebRequest myRequest;
myRequest = WebRequest.Create(@"http://yoururlhere/");

myRequest.UseDefaultCredentials = true;

WebResponse myResponse = myRequest.GetResponse();

Stream ReceiveStream = myResponse.GetResponseStream();
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");

StreamReader readStream = new StreamReader(ReceiveStream, encode);

return readStream.ReadToEnd();
}

This will stuff your webform into a string for use how ever you would like. The great thing is that it pulls in the whole page so you won't have to worry about the tags from your masterpage not being included also.

kaelle
  • 467
  • 2
  • 14
  • 22
0

To me this sounds like you could do this with a user control, and then render the user control output into a string using the following code:

public class ViewManager {
    public static string RenderView(string path, object data) {
            Page pageHolder = new Page();
            UserControl viewControl = (UserControl) pageHolder.LoadControl(path);

            if (data != null) {
                    Type viewControlType = viewControl.GetType();
                    FieldInfo field = viewControlType.GetField("Data");
                    if (field != null) {
                            field.SetValue(viewControl, data);
                    }
                    else {
                            throw new Exception("ViewFile: " + path + "has no data property");
                    }
            }

            pageHolder.Controls.Add(viewControl);
            StringWriter result = new StringWriter();
            HttpContext.Current.Server.Execute(pageHolder, result, false);
            return result.ToString();
}

This code fires all the normal events in the control, and you can load the posted form data into the via a Data property in the control.

This code was lifted from Scott Guthries blog post here.

Regards

Jesper Hauge

Hauge
  • 1,709
  • 15
  • 25