DocumentViewer dynamic loading
Problem reported by Roel Winkels - June 8, 2016 at 2:01 AM
Good morning,
At our company we build an ASP.NET webforms application. We are considering using the DocumentUltimate product for mainly opening PDF and MS Office files. I have implemented some code to make the viewer work. We show a normal default.aspx page on where we open a tab to show some content and the DocumentViewer. So if we add the DocumentViewer in a normal way it will not work because we already loaded the page, the header is rendered and the control is to late to add viewer.js to the head of the DOM. To get rid of this problem we added some code in our OnPreRender method which does this for us:
if (Page.IsPostBack)
               MethodInfo info = typeof(DocumentViewer).GetMethod("GetScriptTags"BindingFlags.Instance | BindingFlags.NonPublic);
               string[] script = (string[])info.Invoke(documentViewer, new object[0]);
               for(int i = 0; i < script.Length; i++)
                   ScriptManager.RegisterClientScriptBlock(thisthis.GetType(), "tsfpreview" + i.ToString(), script[i], false);
After this the viewer still not works, so I looked in viewer.js and took the code which renders the documents and put them in my own script as follows:
TSFMainScript.AppendScript(string.Format(@"var element = document.getElementById('{0}');
                    // Find the script within the panel which is added by the control and move it to the header.
                     for (var i = 0; i < documentViewersToRender.length; i++)
                     // Empty the viewers so it is not rendered double when there are multiple viewers on the page.
                     documentViewersToRender = [];
After this the viewer starts working and we can use it like we want. On the page we have a grid and next to that the DocumentViewer. A certain column in the grid contains a path to a document, so when we switch rows in the grid we take this path and set it to DocumentViewer.DocumentPath, append the upper code again (each request) and update our updatePanel where it stands on. 
This still works great and the DocumentViewer is showing the correct files after each row switch. 
The main problem we are facing now is that the viewer stops working in IE and Edge after 3 or 4 row switches.
In Chrome and Firefox the DocumentViewer keeps working.
The only difference I can spot is that when a document is fetched with partial Content request, the last one is missing when the DocuemntViewer stops working. Also I don't see DecryptWorker.js passing by, which I do see when the viewer works.
I hope you can help me and point me in the right direction. If we cannot fix this we have to look for another product to show our documents.
If you need more information please let me know.
Kind regards,
Roel Winkels

2 Replies

Reply to Thread
Cem Alacayir Replied
Employee Post
Firstly you are using the control in a wrong way, DocumentViewer is not only a client-side control. As of current version, when you want to load another document you need to reload the host page so that the server-side prepares the document properly and then loads the client-side viewer.
Having said that, you do not need .Net reflection magic to render the control, you can just cast the control to IHtmlStringControl interface to access the necessary rendering to string methods:
var documentViewer = new DocumentViewer();

var htmlStringControl = (IHtmlStringControl) documentViewer;
So what you need to do is use an iframe in your page and when a row is clicked in your grid, you should change the location of this iframe like myDocViewer.aspx?f=somefile.doc. In host page myDocViewer.aspx you should get the file (or some kind of ID) from the querystring and then set documentViewer.DocumentPath property to that.
Your problem is not about IE or Edge. Possibly you are causing a memory leak because you are injecting the scripts every time you change a document and thus the browser causes weird rendering problems.
Cem Alacayir Replied
Employee Post
FYI, after v3.9 rendering API is changed and you can render a component as string via these new methods:
var documentViewer = new DocumentViewer();

//Render head as string (which should go into <head> tag)
string head = ComponentRenderer.RenderHead(documentViewer);

//Call this before RenderBody to save session state
//If you don't know requestPath, you can pass string.Empty, it's only used for calculating stateId.
ComponentRenderer.SaveState(documentViewer, Context.Request.Path);

/Render body as string (which should go into <body> tag)
string body = ComponentRenderer.RenderBody(documentViewer);

Reply to Thread