DNN Forums

Ask questions about your website to get help learning DNN and help resolve issues.

Render module / control to HTML

 8 Replies
 2 Subscribed to this topic
 26 Subscribed to this forum
Sort:
Author
Messages
New Around Here
Posts: 7
New Around Here

Hi,

I've developed a web-form module for DNN which is working nicely (thanx to everyone for the guidance, samples etc.)

My customer has now ask for a new feature - to export a page (module only, with styling etc.) to PDF. There are a multitude of HTML to PDF controls available (OS / paid) that I can use, but they all require a reference to the source HTML. I don't want to export the entire page (menus, header bar etc.) - just the content of my module (one specific control ascx) with the various CSS styles so that it displays nicely.

How would I go about doing this?

My basic module control has an empty container that I load a control (that inherits from PortalModuleBase) into when the page loads - based on the 'type' of request being performed by module. This is working and dynamically loads the various controls as I navigate through my modules.

On one of the controls (when viewing the details of an item), I have added a link that the user can click on to Export the details. I want this to load my ExportControl.ascx into memory, render it as HTML (ideally to a stream, but for now an HTML file will work as well) that I can then pass to the PDF library to generate the PDF.

I have the following in place:

When I click on the link, my Export control is loaded and the HTML is rendered to a file (sounds good so far). However:

  1. none of the data on the page is actually rendered - the page load event doesn't seem to fire, so no data is loaded
  2. the module is not complete HTML - it is just a sub-set of an HTML document - no ,
    or tags are created

How do I ensure that the control's Page_Load event etc. all fires and populates as expected? Is it possile to load this in another page (like target="_blank") and then somehow export to PDF (can't force them to use Chrome)? What is the recommended method to achieve this?

When I click on the link - it calls a static method in a helper class to generate a MemoryStream with the rendered HTML and writes to a file (so I can debug etc.):             using (var memoryStream = ModuleRenderHelper.RenderModuleToMemoryStream("~/DesktopModules/MyModule/Manager/Controls/ExportItemDetails.ascx", this))             {                 // Example: Convert the stream to a string for display                 using (var reader = new StreamReader(memoryStream))                 {                     string renderedHtml = reader.ReadToEnd();                     File.WriteAllText(@"C:\Users\Public\Documents\MyPage.htm", renderedHtml);                 }             }      

My helper method is as follows:

        public static MemoryStream RenderModuleToMemoryStream(string modulePath, PortalModuleBase control)         {             // Step 1: Load the ASCX module control             var moduleControl = control.LoadControl(modulePath) as RoQIModuleBase;

            if (moduleControl == null)             {                 throw new InvalidOperationException("Unable to load the module control.");             }             var page = control.Page;

            // Step 2: Prepare a MemoryStream to capture the HTML output             var memoryStream = new MemoryStream();

            using (var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8, 32768, true))             {                 using (var htmlWriter = new HtmlTextWriter(streamWriter))                 {                     moduleControl.ModuleConfiguration = control.ModuleConfiguration;                     // Step 3: Render the module control directly                     moduleControl.RenderControl(htmlWriter);                     htmlWriter.Flush();                 }

                // Reset the memory stream position to the beginning for reading                 memoryStream.Position = 0;

                // Return the memory stream containing the rendered HTML                 return memoryStream;             }         }

Any help would be greatly appreciated.

TIA, Alon

Veteran Member
Posts: 838
Veteran Member
3 Helpful Replier
Helpful Replier
Thanks for being such a helpful replier!
New Poster
New Poster
Congrats on posting!

Perhaps not the answer you're looking for but I created a similar thing for https://www.schutte-usa.c...Id/468/Cable%20Ties#

If you hit the download button, it creates a PDF of the product based on the values in the database. In this particular case, the pdf is created as an action within the module ActionForm. As I use Plant an App, this module is part of the suite. As you can see, the PDF does not print the page but is entirely custom. Als taking into account the product category and the language.
If ActionForm is not sold seperately, you might want to take a look at Live Forms and the PDF add on. Maybe a bit fewer options but much cheaper.

If you want to build it yourself, consider using 2sxc. A lot of good stuff is already in that platform and pdfStream as well. 

Cheers

New Around Here
Posts: 7
New Around Here
Hi Tycho,

Thanx for getting back to me - much appreciated.
The company is a startup, so at this stage they want to keep the costs very low (or non-existent).
This basically rules out Plant an App.

From memory, 2sxc works with Razor and not web-forms.
Maybe the solution is to develop a new module for render to PDF functionality rather than using my existing one.

Thanx,
Alon
Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!

There are a lot of ways to do this, and the HTML can be output and/or fed into the various PDF generation APIs in many ways too.  We recently did this, and used a localized solution, where most of the HTML was contained in a localization file to allow for editing, and it gets fed through a method which replaces some placeholders, before presenting the PDF as a download.  It only depends on whether or not the PDF generator is a good one, and how you want the UX to be. 😎

New Around Here
Posts: 7
New Around Here

Posted By wizard on 1/24/2025 7:34 PM

Hi Will,

Thanx for responding - much appreciated.

The / control PDF is supposed to list the history of a 'conversation' (much like this one) including details of attachments (which will be downloaded in a zip file). Only the field labels could really be localized - the rest is simply HTML text captured in CKEditor for each conversation entry.

As for the UX - on my current form I have added an Export button. Clicking this should render the export control (rendered optimised for PDF), generate the PDF, zip the PDF and all the attachments relating to the conversation into a single Zip file, and download it.

I've got the zip and download part working - all I'm missing at this stage is the ability to render the ascx control as HTML (or a stream), which contains all the data related to the conversation, to feed into the PDF library.

I'm still looking at various HTML to PDF libraries to find one that is reasonably priced (or OSS) and capable of handling HTML to PDF.

Thanx, Alon

Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!

Well, one way to do this is to use a client-side API call to pass the output HTML to the PDF generation code.  If the PDF tooling you're using doesn't support this, you could easily do this for yourself by creating a web API endpoint in your custom module(s) to accept a chunk of HTML and then use that to generate the desired PDF.  

New Around Here
Posts: 7
New Around Here

Hi Will,

Is there a way to get the rendered HTML from a control .ascx without setting that control to be the current one?

I've tried calling LoadControl(controlPath) which returns an instance of the control, and when I rey return the rendered HTML - none of the events inside the control had fired (like Page_Load) so none of the data used within the control was available.

Thanx,
Alon

New Around Here
Posts: 7
New Around Here

So, I 'hacked' this a bit in order to get this resolved.

The issue I had is that when I loaded the control.ascx - it didn't fire any of the internal events (like Page_Load) etc.
Even when I created a new Page object and loaded the control into the page - the events weren't firing.
As a result - none of the data was loaded and the control rendered without any of the actual data being present.

So I haved it - I created a method on my control (called ForceLoadData), and just before I render the page / control using RenderControl(htmlWriter), I call ForceLoadData which in turn calls the Page_Load event with all the code to load the data etc.

While it is a bit of a hack - it seems to be working nicely.

Senior Member
Posts: 1607
Senior Member
MVP
MVP
You're an MVP!
New Poster
New Poster
Congrats on posting!

Yeah, it gets a bit tricky to load a control dynamically with all of it's events.  It's a bit more code to make it all load properly.  However, that would have been more of a "hack" then what you did, maybe.  The most straightforward approach (in my opinion) would have been my original suggestion.  But, if it works, that's all that matters now. 😎 🙌🏽

These Forums are for the discussion of the open source CMS DNN platform and ecosystem.

For the benefit of the community and to protect the integrity of the ecosystem, please observe the following posting guidelines:

  1. If you have (suspected) security issues, please DO NOT post them in the forums but instead follow the official DNN security policy
  2. No Advertising. This includes the promotion of commercial and non-commercial products or services which are not directly related to DNN.
  3. No vendor trolling / poaching. If someone posts about a vendor issue, allow the vendor or other customers to respond. Any post that looks like trolling / poaching will be removed.
  4. Discussion or promotion of DNN Platform product releases under a different brand name are strictly prohibited.
  5. No Flaming or Trolling.
  6. No Profanity, Racism, or Prejudice.
  7. Site Moderators have the final word on approving / removing a thread or post or comment.
  8. English language posting only, please.

Would you like to help us?

Awesome! Simply post in the forums using the link below and we'll get you started.

Get Involved