DocumentViewer dynamic loading
Problem reported by Roel Winkels - June 8, 2016 at 2:01 AM
Resolved
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.
                    jQuery(element).find('script').appendTo(document.head);
 
                     for (var i = 0; i < documentViewersToRender.length; i++)
                        renderDocumentViewer(documentViewersToRender[i]);
 
                     // Empty the viewers so it is not rendered double when there are multiple viewers on the page.
                     documentViewersToRender = [];
                    "this.panel.ClientID));
        }
 
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

11 Replies

Reply to Thread
0
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;
htmlStringControl.RenderCss();
htmlStringControl.RenderJs();
htmlStringControl.RenderControl();
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.
0
Roel Winkels Replied
Thank you very much, I will look in to it :)
0
Roel Winkels Replied
Cem,

This fixed my problem and the document viewer is now working properly :)

I was aware it was a server side tool, I already rendered it from the server. I now create an iframe where i normaly created the documentViewer and added an aspx page (with a documentViewer on it) to this iframe and parsed the needed paramters with the querystring as you suggested. Setting the DocumentPath to the DocumentViewer on the aspx page solves the problem I was facing :)

Thanks again!
0
Cem Alacayir Replied
Employee Post
Hi Roel,
I am glad you got it working. This is the usual and safe way to use the DocumentViewer. Yes you were rendering it from the server but the control depends on the normal ASP.NET page cycle to save some state about the document so it may not be fully AJAX or UpdatePanel compatible. We may add support for changing the document from client-side or when in an UpdatePanel in future versions.
0
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);
 
0
Cem Alacayir Replied
Employee Post
Hi Sandeep,
After v3.9, rendering API is changed, there is no more IHtmlStringControl. See below for my reply which shows the new API usage.
0
Sandeep Mohanadasan Replied
Hi Cem,

Document is not loading after 4 to 5 instance on IE.It is working fine on chrome.Could you please help me on this.
Note:I am using Ver 3.13.0.0 ,i am not able access ComponentRenderer.

Below is my code

----------------------------------------------------------
@using GleamTech.AspNet.Mvc
@using GleamTech.DocumentUltimate
@using GleamTech.DocumentUltimate.AspNet
@using GleamTech.DocumentUltimate.AspNet.UI

<!DOCTYPE html>

@{

var documentViewer = new DocumentViewer
{
Height = 900,
Document = ViewBag.URL//URL passed from controller

};

}
<html>
<head>
<title>Document Viewer</title>
@this.RenderHead(documentViewer)
</head>
<body>
@this.RenderBody(documentViewer)
</body>
</html>
------------------------------------------------------------------------------------------
0
Cem Alacayir Replied
Employee Post
ComponentRenderer is for "render to string" only (i.e. for manual rendering without depending on our MVC or WebForms helper methods/extensions), if you are using MVC you can already access this.RenderHead and this.RenderBody methods so you don't need it.

>Document is not loading after 4 to 5 instance on IE

This is probably because you are loading head multiple times. RenderHead should be rendered only once in your <head> tag. You can call RenderBody multiple times.
This is already demonstrated in this MVC partial view example:
https://demos.gleamtech.com/documentultimate/mvc.cs/#DocumentViewer/UsingPartial
0
Sandeep Mohanadasan Replied
Hi Cem,

Great thanks for your support.

I have many documents (more than 20) in the application.Each time when user clicks the link the document preview should open in new window.So i have to call the view which has @this.RenderHead(documentViewer) method.I can't make use of the partial view concept as mentioned in the link.

i am facing the issue on loading after 4th or 5th call.

Please note,it is working fine in chrome .

It will be a great help ,if you can help on this
0
Cem Alacayir Replied
Employee Post
The proper way to do is using the partial view. Why can't you use it? Just see the sample code, it's pretty easy. You can load as many documents in the partial view just like a full view, the key point is separating RenderHead and RenderBody into 2 different views so that you can call the second one many times.

It can work in Chrome because it has better memory management but what you are doing is wrong and very inefficient (adding same js files to the page multiple time) thus you see it fails in IE (or some other browser).

Second option is using an iframe for the viewer. Search the forum for it.
0
Sandeep Mohanadasan Replied
Hi Cem,
Thanks for the quick reply.The issue is ,I have 20 different links in application corresponds to different documents.Each time when i click link ,it has to open in new window.So i have to call main view each time .

Reply to Thread