0

I am using PDFConverter to save a "Receipt page" onto the computer. The way it's set up is I am using a link from Page X to Response.Redirect() to Receipt Page, so it transfers the session data.

Then I am using Session["Cart"] Data to populate the table with the data from the receipt. The problem is, when I use Winnovative PDFConverter to save the page to a file, it doesn't save the table. That's because the table doesn't get populated as Session data isn't sent, (or it creates a new Session, not sure) and as such my saved file does not contain the table, which is the whole point of the Receipt page. How do I get around this? I found a "workaround" online but it doesn't seem to work. It won't even save the file, instead returning an error.

protected void Save_BtnClick(object sender, EventArgs e) 
    {
        PdfConverter converter = new PdfConverter();
        string url = HttpContext.Current.Request.Url.AbsoluteUri;

        StringWriter sw = new StringWriter();
        Server.Execute("Receipt.aspx", sw); //this line triggers an HttpException
        string htmlCodeToConvert = sw.GetStringBuilder().ToString();

        converter.SavePdfFromUrlToFile(htmlCodeToConvert, @"C:\Users\myname\Downloads\output.pdf"); // <--not even sure what method i should be running here

        //converter.SavePdfFromUrlToFile(url,@"C:\Users\myname\Downloads\output.pdf"); <-- this saves it without the table
    }

EDIT: One solution I thought of was is it possible to use Winnovative's ability to grab certain elements of the page to pass in the already populated table instead of trying to generate the page automatically using the method? I'm not 100% sure how to work it based on the documentation alone and I do not have access to the sample codes.

Soulzityr
  • 406
  • 1
  • 8
  • 26

2 Answers2

1

I don’t know why the Server.Execute is throwing an exception, but here is an alternative to using that call.

You are using Server.Execute to get the web page to convert to HTML. Instead of that approach have Winnovative make that call. The trick is to allow that page request to access the current user’s session. You specify the URL to call and then supply the user credentials in the cookie collection of the PDFConverter.

See this page and choose the approach based on your authentication technique.

Winnovative Authentication Handling

Edit:

@LordHonydew, We have gone in a big circle in the comments and ended up at the beginning. Let me try this again.

First, in the Server.Execute exception is there an inner exception? There could be more information that helps explain what is going wrong. Even after fixing that issue there are other items that must be fixed.

Second, when using Winnovative to generate a PDF from a web page that is secured you must provide credentials to the PDFConverter so that it can access the page and its resources. There are a couple of ways winnovative can get the HTML: one is by giving the PDFConverter the URL to call and another is to use the Server.Execute to get the HTML directly and then provide the PDFConverter with the HTML, which is how you are doing it. Either way the PDFConverter still needs to talk to the server to get the additional page resources. Things like images and CSS files are not in the HTML, they are referenced by the HTML. The converter will make calls to the server to get these items. Since your application is secured you must provide the converter with credentials to access the server. We will do this by using the same authentication cookie that is used for each page request. There are other ways such as supplying user name and password. That link above explains the various ways.

This code gets the auth cookie from the current request and gives it to the converter:

pdfConverter.HttpRequestCookies.Add(FormsAuthentication.FormsCookieName,
     Request.Cookies[FormsAuthentication.FormsCookieName].Value);

Finally, the converter.SavePdfFromUrlToFile is not the right method to use. That would only save the receipt to the local server’s drive. You need to stream it back to the user.

Try the following. Set a breakpoint in the catch block so you can see if there is an inner exception.

protected void Save_BtnClick(object sender, EventArgs e)
    {

        // Get the web page HTML as a string
        string htmlCodeToConvert = null;
        using (StringWriter sw = new StringWriter())
        {
            try
            {
                System.Web.HttpContext.Current.Server.Execute("Receipt.aspx", sw);
                htmlCodeToConvert = sw.ToString();

            }
            catch (Exception ex)
            {
                // set breakpoint below and on an exception see if there is an inner exception.
                throw;                    
            }
        }

        PdfConverter converter = new PdfConverter();
        // Supply auth cookie to converter
        converter.HttpRequestCookies.Add(System.Web.Security.FormsAuthentication.FormsCookieName,
            Request.Cookies[System.Web.Security.FormsAuthentication.FormsCookieName].Value);

        // baseurl is used by converter when it gets CSS and image files
        string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority +
            Request.ApplicationPath.TrimEnd('/') + "/";

        // create the PDF and get as bytes
        byte[] pdfBytes = converter.GetPdfBytesFromHtmlString(htmlCodeToConvert, baseUrl);

        // Stream bytes to user
        Response.Clear();
        Response.AppendHeader("Content-Disposition", "attachment;filename=Receipt.pdf");
        Response.ContentType = "application/pdf";
        Response.OutputStream.Write(pdfBytes, 0, pdfBytes.Length);
        HttpContext.Current.ApplicationInstance.CompleteRequest();

    }
Gridly
  • 938
  • 11
  • 13
  • Hello thanks for the response. I am a bit confused by what you are saying, and I don't know what you mean by authentication technique. From the link you sent me, it seems the only thing I am doing is setting the License Key with a "pdfConverter.LicenseKey = "B4mYiJubiJiInIaYiJuZhpmahpGRkZE=";" It saves the pdf just fine. So if I understand you correctly, use Winnovative on my original URL call, just also create and send the necessary cookies to generate the table? – Soulzityr May 19 '14 at 21:14
  • By authentication technique I mean how the user is authenticated - Windows or Forms. And yes, my point is that you need to supply the cookies so that the request made by Winnovative has access to the same session information. – Gridly May 19 '14 at 22:09
  • I must have missed something important because I don't understand why I need to authenticate the user. As for sending as a cookie, I currently have Session["ProductCart"] and sure I can create a cookie but how do I have the pageload know to grab the cookies INSTEAD of the session data? And how do I store session data into a cookie? Do I have to translate into a string, put the string into the cookies, pass the cookies into winnovative method, and have a condition for page load to handle cookies instead of session data? – Soulzityr May 19 '14 at 23:38
  • @LordHoneydew, so this process does not require the users to log in? – Gridly May 20 '14 at 15:26
  • It does, they are logged in but they won't see the option to save unless they are logged in and at the final receipt? Also could you help me with my cookies question? Sorry, I am struggling a bit with this. If I don't know how many items are in the cart, how do I pass all those items into cookies, since I need to make them into strings first. For the record, I'm doing this to learn, primarily :) That may explain my novice ability. – Soulzityr May 20 '14 at 16:39
  • You don't pass them in a cookie. The cookie is used to pass credentials used to see the Session information. Steps: user posts back the request, you collect the information and store it in Session, Use Winnovate to generate the PDF which calls the web form, in the web form get the information from the Session. – Gridly May 20 '14 at 18:05
  • Yes, this goes back to my original question from the start. My web form already gets information from Session. Winnovative generates a new Session whenever I use it to save to File. In other words Session["Cart"] doesn't exist. I need to pass this Session data to Winnovative. In other words, my web form currently does this - (Get Session["Cart"]. Generate the table with the data from Session["Cart"]. User then clicks save. Save will save the web page. HOWEVER, it creates a new session when doing so. Therefore, Session["Cart"] does not exist, so when I save, the table comes up empty. – Soulzityr May 20 '14 at 20:42
  • Hello thanks for bearing with me and being patient. I have no cookies up to this point, just a bunch of data stored in Session. I need to create the cookies with the authentication and then assign them to the pdfconverter? I made an alternate method but this line gives me an error: converter.HttpRequestCookies.Add(System.Web.Security.FormsAuthentication.FormsCookieName, "Request.Cookies[System.Web.Security.FormsAuthentication.FormsCookieName].Value);" It says "HttpRequestCookies" is an unknown member of pdfconverter. I don't think I'm missing any imports. – Soulzityr May 21 '14 at 20:53
  • On a side note, I was originally just sending the url and it was the easiest way I understood how to do it. I changed it to the html way because I was trying to figure out how to send the data from the table. But I understand what you're saying now. I just was confused because documentation said it starts a new Session, not try and fail to access the original session data from the server – Soulzityr May 21 '14 at 20:57
  • Okay sorry it took me so long to wrap my head around this. I understand exactly what I need to do now. I will edit my question if it works. I authenticate through username/password so I will just set those fields inside my pdfconverter. MY question about streaming the file, how do I let them specify where to save it? or will the browser automatically do that? – Soulzityr May 21 '14 at 22:42
  • The lines of code that talk about the auth cookie are used so you don't have to supply the username/password. The "Content-Disposition" header instructs the browser to display the file save dialog, so yes the browser will automatically do that. No problem on how long it took. There were a couple of things going on. – Gridly May 22 '14 at 00:42
1

Please check the Convert a HTML Page to PDF in Same Session demo. You can find there a description of the method to use to preserve the session data during conversion and the C# sample code. The code below is copied from there :

protected void convertToPdfButton_Click(object sender, EventArgs e)
{
    // Save variables in Session object
    Session["firstName"] = firstNameTextBox.Text;
    Session["lastName"] = lastNameTextBox.Text;
    Session["gender"] = maleRadioButton.Checked ? "Male" : "Female";
    Session["haveCar"] = haveCarCheckBox.Checked;
    Session["carType"] = carTypeDropDownList.SelectedValue;
    Session["comments"] = commentsTextBox.Text;

    // Execute the Display_Session_Variables.aspx page and get the HTML string 
    // rendered by this page
    TextWriter outTextWriter = new StringWriter();
    Server.Execute("Display_Session_Variables.aspx", outTextWriter);

    string htmlStringToConvert = outTextWriter.ToString();

    // Create a HTML to PDF converter object with default settings
    HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter();

    // Set license key received after purchase to use the converter in licensed mode
    // Leave it not set to use the converter in demo mode
    htmlToPdfConverter.LicenseKey = "fvDh8eDx4fHg4P/h8eLg/+Dj/+jo6Og=";

    // Use the current page URL as base URL
    string baseUrl = HttpContext.Current.Request.Url.AbsoluteUri;

    // Convert the page HTML string to a PDF document in a memory buffer
    byte[] outPdfBuffer = htmlToPdfConverter.ConvertHtml(htmlStringToConvert, baseUrl);

    // Send the PDF as response to browser

    // Set response content type
    Response.AddHeader("Content-Type", "application/pdf");

    // Instruct the browser to open the PDF file as an attachment or inline
    Response.AddHeader("Content-Disposition", String.Format("attachment; filename=Convert_Page_in_Same_Session.pdf; size={0}", outPdfBuffer.Length.ToString()));

    // Write the PDF document buffer to HTTP response
    Response.BinaryWrite(outPdfBuffer);

    // End the HTTP response and stop the current page processing
    Response.End();
}


Display Session Variables in Converted HTML Page

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        firstNameLabel.Text = Session["firstName"] != null ? (String)Session["firstName"] : String.Empty;
        lastNameLabel.Text = Session["lastName"] != null ? (String)Session["lastName"] : String.Empty;
        genderLabel.Text = Session["gender"] != null ? (String)Session["gender"] : String.Empty;

        bool iHaveCar = Session["haveCar"] != null ? (bool)Session["haveCar"] : false;
        haveCarLabel.Text = iHaveCar ? "Yes" : "No";
        carTypePanel.Visible = iHaveCar;
        carTypeLabel.Text = iHaveCar && Session["carType"] != null ? (String)Session["carType"] : String.Empty;

        commentsLabel.Text = Session["comments"] != null ? (String)Session["comments"] : String.Empty;
    }
}
Winnovative
  • 118
  • 7