I am using an ASP.Net MVC site that has a link to an ASP.Net WebForms page that performs the actual download. I would like my jquery ui dialog to close when the download starts. Is there a javascript/jquery event that I can use to accomplish this?
I found an example with exactly what I want to do here, but since I'm using MVC instead of WebForms I can't seem to get it to work.
Two possibilities:
Target your form at a hidden <iframe>, and close your dialog from a "load" handler on the window object in the <iframe>
Have the client create a random string and post it with the form, and then start a polling loop to check document.cookie to see if it contains the random string. The server should set a cookie whose value is that random string, and it should do that in the header for the file being sent out. When the client polling loop sees the cookie, it can close the dialog.
Related
I have a performance issue where we have a 2 page setup as part of a workflow in a bigger system. This section is dedicated to rendering reports allowing users to chose their own parameters.
Page1.aspx collects parameter information for a report. It takes the information submitted on a form and validates it. If it validates OK, it stores the selections in the DB as XML, then redirects to Page2.aspx with the run id in the query string. Simple enough, performance is great.
Page2.aspx pulls the ID out of the DB and hydrates a Crystal ReportDocument object (taking milliseconds) then we call ExportToHttpStream which then renders the report as a PDF or DOC or XLS download (output format is determined in Page1.aspx). The performance of the ExportToHttpStream method is very poor due to the way our reports are written and DB indexes on the target system. This is outwith my control at the moment but I am promised that they are being worked on.
So the problem is, that when the submit button in Page1.aspx is pressed, the user experiences a very long delay before the download starts. It is then compounded by the user pressing the submit button again thinking there is a problem.
I think what I need to do is have Page1.aspx redirect to Page2.aspx. Page2.aspx should render the master page furniture and a loading div, and the report should render asynchronously somehow in the background before the save dialogue automatically pops up, after this i'd like to change the loading div to a 'Report generated, click here to go back'.
If this is the best way to achieve this, how can I load a full page, then request the report asynchronously? I'm open to any suggestions here.
You could use ajax to load the report on Page2.aspx and show a loading message while it's processing.
Look at the jQuery.load() method. This might be the easiest way to accomplish what you are trying to do.
Page1.aspx - collect parameters
Page2.aspx - report view, calls Page2Details.aspx via ajax.
Try loading Page2.aspx inside iframe and use jQuery to display waiting indicator and hide it after Page2.aspx download
Whilst both answers gave me some ground to go out and research in the right direction. My solution included using the fileDownload plugin from John Culviner to facilitate a similar solution:
jQuery fileDownload by John Culviner
This allowed me the following page structure:
Page1.aspx, gathers and validates parameters for the report and puts them into Oracle.
Page2.aspx, whilst passed in the runid (pointer to the parameters in the db) via the query string setup 3 hidden divs. Loading, Error and Success.
The script mentioned above was employed at this point. jQuery firstly sets the loading div visible then calls the plugin. The plugin dynamically creates an iframe and downloads the binary (xls/doc/pdf) from Page3.aspx. It then fires a success callback or failure. The success callback is fired by means of a cookie set at the end of the response in Page3.aspx.
I believe the plugin mentioned downloads using a 'text/plain' AJAX call in jQuery avoiding the limitation of there not being an octet-stream equivalent in AJAX.
It works, its not the cleanest solution by any means, it doesn't degrade one bit, but provides the users on our controlled intranet with an extremely responsive and pleasing UI.
I have a web page and a modal dialog page. On clicking the save button in the show modal dialog. closes the window and returns a value. Now when the
control reaches the JavaScript function of the parent window . I wnt to perform some database operation on the basis of this returned ID.
I am using the following approach to utilize this returned value.
Keeping it in the hidden field and populating the returned value in hidden control.
keeping a hidden button in the parent window, performing the click event when control comes back to JavaScript function of the parent page. Thus in the server side button handler get the value from hidden field and perform database operation on the basis of returned value.
Is this approach fine. Or I can get rid of hidden field
That's not terribly bad provided the ID returned is not sensitive information that someone can use to modify a record that doesn't belong to him. One can perfectly manipulate this ID on the client side for any other ID and have your logic update a different record from what you intended.
If all you are doing is calling a server side method passing this ID; why don't you do the whole update from the pop-window itself (at that point you already know the ID)?
If the parent window (page) is meant to be updated; you can just perform a normal refresh of the page (ie. use window.location to redirect the user to the same page so he can see the update or use Response.Redirect to the same page.)
What you're probably looking for is called AJAX. With AJAX you can communicate with your web server from within your JavaScript code directly. No HTML form posts are required then. You might want to look at frameworks like JQuery. These have easy implementations (cross browser wrappers) to send HTTP requests via AJAX.
Note: I just noticed, you are using ASP.NET. Take a look at ASP.Net AJAX Page Methods.
I'm retro-fitting a .aspx page with AJAX functionality (using VB, not C#). The codebehind populates the page with data pulled from a web-service. The page has two panels that are populted (with different data, of course) in this way. On a full page refresh, one or both panels might need to be populated. But populating Panel 2 can take a long time, and I need to be able to update panel 1 without refreshing Panel 2. Hence the need for AJAX (right?)
The solution I've come up with still has the old .aspx page with .aspx.vb codebehind, but introduces a Generic Handler (.ashx) page into the mix. Those first two components do the work on the user's first visit or on a full page refresh, but when AJAX is invoked, the request is handled by the .ashx page.
First question: Is this sound architecture? I haven't found a situation online quite like mine. Originally, I wanted to make the .aspx page into the AJAX handler by having the codebehind implement IHttpRequest, and then providing "ProcessRequest" and "IsReusable" methods, but I found I couldn't separate a regular visit to the page from an AJAX request, so my AJAX handlers took over even on the first visit to the page. Second question: Am I right to think that this approach (making the .aspx page do double-duty as the AJAX handler) will never work? Is it impossible to tell whether we're getting a full-page request or a partial-page (AJAX) request?
If the architecture is good, then I need to dynamically generate a lot of HTML in the .ashx file, right? If that is right, should I send HTML back to the client, or should I encode it in some way? I've heard of JSON encryption, but haven't figured out how to use it yet. So, Third question: Is "context.Response.Write" the only pipeline for sending data back to the client? And, if so, should I send back HTML or some kind of JSON-encoded objects?
Thanks in advance.
It sounds as if the page requires some AJAX functionality added to the UI.
Suggest using an UpdatePanel for each web form element that needs to have AJAXy refresh
functionality. That'll save you from having to refactor a bunch of code, and introduce a whole lot of HTML creation on your .ashx.
It'll be more maintainable over the long run, and require a shorter development cycle.
As pointed out by others, UpdatePanel would be a easier way - but you need to use multiple update panels with UpdateMode property set as conditional. Then you can trigger the update-panel refresh using any button on the page (see AsyncPostBackTrigger) or even using java-script (see this & this). On the server side, you may decide what has triggered the partial post-back and act accordingly by bypassing certain code if not needed.
You can also go with your approach - trick here is to capture the page output using HttpServerUtility.Execute in your ashx and write it back into the response (see this article where this trick has been used to capture user control output). Only limitation with this approach is that you can only simulate GET requests to your page and so you may have to change your page to accept parameters via query string. Personally, I will suggest that you create a user control that accept parameters via method/properties and will generate necessary output and then use the control on your page and in ashx (by dynmaically loading it in a temperory page - see this article).
EDIT: I am using jquery to illustrate how to do it from grid-row-view.
$(document).ready(function() {
$("tr.ajax-grid-row").click(function() {
$("#hidden-field-id").val($(this).find(".row-id").val()); // fill hidden filed
$("#hidden-button-id").click(); // simulate button click
});
});
You can place above script in the head element in markup - it is assuming that you have decorated each grid-row-view with css class "ajax-grid-row" and each row will have hidden field decorated with css class "row-id" to store row identifier or the value that you want to pass to server for that row. You can also use cell (but then you need to use innerHTML to get the value per row). "hidden-field-id" and "hidden-button-id" are client ids for hidden field and submit button - you should use Control.ClientID to get actual control ids if those are server controls.
JSON is not for that purpose, it is to pass objects serialized with a nice light weight notation, is you need to stream dinamically generated html using ashx, response.Write is what you have. You may want to take a look at MVC
Or you could use jquery if it's just html, the simpliest would be the load function, or you can look into Ajax with jquery. Since the ashx can be served as any resource it can be used in the load function.
I agree with #p.campbell and #R0MANARMY here. UpdatePanel could be the easiest approach here.
But then like me, if you don't want to go the UpdatePanel route, I don't see anything wrong with your approach. However, generating the html dynamically (entirely) at the back end is not a route I'll personally prefer (for the maintainence reasons). I'd rather prefer implementing a solution that will keep the design separate from the data.
What are the different ways of communication between asp.net page and a popup page? Query strings etc. Which is most secure?
You say "communication between" the pop-up and the main ASP.NET page. First, I assume that the pop-up is an ASP.NET page as well so the communication from the main page to the pop-up is no different from the communication from one page to the next in a series of pages. That is, you can store and then use data in the session (if the data is available when the main page is loaded), via query strings, etc. Unless the data is sensitive, the simplest way by far is to include a variable in the call to the pop-up that is replaced by the appropriate arguments. Here is a sample image link:
<img style='cursor:hand;' alt="Open Note" onclick="javascript:window.open('NoteEdit.aspx?T=3&UID=<%#NoteUID%>', 'Note', 'HEIGHT=400,WIDTH=420');" src="images/Note.gif" />
Note the "NoteUID" replacement argument.
The more interesting question is how to pass information back to the window that popped up the pop up. To do that, start with this javascript:
<script type="text/javascript">
function OpenHRAResults()
{
opener.location.href="<%#DestName%>";
window.close();
}
</script>
This is taken from code where I re-open a specific page but, as you can guess, you can do all sorts of things with the "opener" window (the window that popped-up the pop up).
Hope this helps...
If you are talking about an actual pop-up page, where you are using window.open from javascript. You have the querystring and Javascript as your only real available options for passing information between.
As for "security" of this. The users will be able to see anything via a querystring, JavaScript can move values across, but they would be existing on the other page. But you could pass something like an excrypted value to make things more secure.
We try to avoid query strings where possible in sometimes they are just too convenient. In those cases we always encrypt the querystring. There are several ways to do this - example of one approach:
http://www.codeproject.com/kb/web-security/querystringencryptionnet.aspx
A few methods
Query strings (window.open('/users/123'..)
Javascript (window.opener)
HTTP POST (open a popup via javascript, set the form target to it's name as target and post)
Sessions or other server side methods
In answer to the security consideration I'd say that query strings in combination with server side security is the way to go. Open the popup passing the information via query strings, then validate that the logged in user has permissions to access that user. Some specific requirements would call for encrypting the querystring data.
For delete operations I'd probably use a postback to avoid problems like "my indexing spider deleted all users".
You don't need to sent the real data to the popup window. Just create a GUID on the opener page.
Create a class in asp.net which represent all the data you need to sent between the popup page and the opener page. For example popupdata
Store the serialized class in the Session with the GUID as the name Session[Guid] = class object
Session[Guid] = popupdata;
Open the popup with f.i. ~/popupwindow.aspx?PageID=Guid
Retrieve the session object with calling the Session[Guid] again (Guid is coming from the PageID querystring.
so on the popup page call popupdata data = (popupdata)Session[Guid];
And then do whatever yuo like withthe data.
If data is changed on the popupwindow you can store it in the Session variable again
and send it back to the opener...
Very secure since no data is sent to the client.
In my ASP.Net application I have a requirement that when a user clicks on an UI element we generate a PDF for them which they can download. This is currently implemented by doing a form post to an ashx page. This page essentially inspects the form and then executes the correct server side page which either results in HTML or a PDF document of that pages HTML.
On the client I know ahead of time if we are going to be getting a PDF or HTML, when its an HTML I open a new window and direct the form post to that window and all works well. When its a PDF I don't change the target for the form and it remains on the current page.
This works, the user is presented with a save dialog, and the current page is not changed or lost.
The problem I have is that generating the PDF takes anywhere from 1-15 seconds. What I want to do is popup a please wait dialog. Displaying the popup is going to be easy, what I am not sure of is how do I know to close the popup? The popup will be a div in the current page.
The popup can have a client side timer which polls the server for task completion. The long running server task should update the progress in a database table or a server cache object which can be accessed by the polling service.
Couple of old articles from MSDN magazine. You should be able to use the same concepts with newer libraries like asp.net Ajax.
Reporting Task Progress With ASP.NET 2.0
Simplify Task Progress with ASP.NET "Atlas"
just have some javascript on the client side and let it show some animated GIF for 1-15 seconds (your choice) and close itself after the designated time.
Gulzar's suggestion was spot on. I have a simple ajax enabled wcf service which checks a session variable. My ashx page sets the variable to false when it starts processing and then true when its done.
I think there might be a race condition if the client checks before we set the session item to false; however, there are ways around that if we modify the service to set the session item to false after a client gets an im done response.
The tricks is still going to be figuring out what the intervalon the client should be. If we set it to low the user could save the file and then see the still processing message. I'm debating myself between half a second and a second. Anything less then a half a second seems unnessecary.
You said:
When its a PDF I don't change the
target for the form and it remains on
the current page.
If that is the case then the original page will be gone when the PDF is opened. In that situation I would have a loading animated gif and open it using Javascript into a div tag overlaying the rest of the page. You would not need to close it, so no timer or polling needed. It would just be gone when the page is gone.