I am using ASP.NET and C#. I am generating pdf and sending that on the pageload using
response.TransmitFile(file);
So after this I need to close this window.I try to write the dynamic script for closing, but that did not work.
On button click i am using this code to open the window.
window.open("Export.aspx?JobNumbers=" + jobnums,'',"resizable=0,scrollbars=0,status=0,height=200,width=500");
On pageload of export.cs I am creating the pdf using itextsharp.Then snding that using this.It is called on the buttonclick of the button that is clicked dynamically using
string script = "var btn = document.getElementById('" + Button1.ClientID + "');";
script += "btn.click();";
Page.ClientScript.RegisterStartupScript(this.GetType(), "Eport", script, true);
This is the onclick event of button.
protected void StartExport(object sender, EventArgs e)
{
response.Clear();
response.ContentType = "application/pdf";
response.AddHeader("content-disposition", "attachment;filename=" + Path.GetFileName(strFilePath));
response.TransmitFile(strFilePath);
response.Flush();
}
After this i need to close this export.aspx window for that i used this.
Page.ClientScript.RegisterStartupScript(this.GetType(), "Export", "window.onfocus=function(){window.close();}", true);
And
HttpContext.Current.Response.Write("<script>window.onfocus=function(){window.close();}</script>");
But did not worked.
Is it possible?
you should try something like this:
<script>
$.get('/call/the/page.aspx'); // Send a request to the page from which you Transmit the file
window.setTimeOut(function() { window.close(); }, 5000);
</script>
This will try to close the window after 5 seconds, leaving enough time for the download to start.
You will have to put this in a page, open that page in a popup window, so this script will execute, request the file, and close itself.
on the body tag html you must set event unload="window.close()" . This worked for me
I'd suggest to write an HttpHandler:
/// <summary>
/// here is your server-side file generator
/// </summary>
public class export : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// get some id from query string
string someid = context.Request.QueryString["id"];
try
{
...
context.Response.ContentType = "application/pdf";
context.Response.HeaderEncoding = System.Text.Encoding.UTF8;
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
context.Response.AppendHeader("Content-Disposition", "attachment; filename=filename.pdf");
context.Response.Write(yourPDF);
/* or context.Response.WriteFile(...); */
}
catch (Exception ex)
{
/* exception handling */
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
do not forget to register it in the Web.config:
<system.webServer>
<handlers>
<add name="/export_GET" path="/export" verb="GET" type="YourNamespace.export" preCondition="integratedMode,runtimeVersionv4.0" resourceType="Unspecified" />
</handlers>
</system.webServer>
after that you just have to call to this handler from javascript like this:
ExportFile: function () {
...
var url = "http://" + window.location.hostname + ":4433/export?cid=" + id;
window.open(url);
}
it will show you save dialog without needing to manually close a new window (it will close automatically).
Since it is obvious that you can't close window that is created by browser as result of downloading a file (like list of downloaded files/do you want to open prompts) I assume the question is "how to close hosting page that initialted "get PDF" operation.
Since there is no way for page to know about completion of downloading of a file you need may need to ask server (i.e. AJAX erquest) if dowload is complete - it will require some server side code for tracking downloads (and you may not be able to use session state for storing download status as it will be locked for other requests). When you got confirmation that download is complete you can close the window. Note that closing window that was opened by the user will either fail or at least show confifmation "Do you really want to close"...
Related
How can I perform the save this page directly in pdf? I know that selenium is not able to control the chrome dialog box ... is there another way?
Page to save in pdf:
This below code will help to save page as pdf in Selenium c#.
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
protected void PDFconversion(ChromeDriver driver, string root, string rootTemp)
{
//Grid.Rows.Add(TxtBxName.Text, TxtBxAddress.Text);
try
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
Thread.Sleep(500);
js.ExecuteScript("setTimeout(function() { window.print(); }, 0);");
Thread.Sleep(500);
driver.SwitchTo().Window(driver.WindowHandles.Last());
Thread.Sleep(500);
string JSPath = "document.querySelector('body>print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#destinationSettings').shadowRoot.querySelector('#destinationSelect').shadowRoot.querySelector('print-preview-settings-section:nth-child(9)>div>select>option:nth-child(3)')";
Thread.Sleep(500);
IWebElement PrintBtn = (IWebElement)js.ExecuteScript($"return {JSPath}");
Thread.Sleep(500);
PrintBtn.Click();
string JSPath1 = "document.querySelector('body>print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('print-preview-button-strip').shadowRoot.querySelector('cr-button.action-button')";
Thread.Sleep(1000);
IWebElement PrintBtn1 = (IWebElement)js.ExecuteScript($"return {JSPath1}");
PrintBtn1.Click();
Thread.Sleep(1000);
SendKeys.Send("{HOME}");
SendKeys.Send(rootTemp + "\\" + "result.pdf"); // Path
SendKeys.Send("{TAB}");
SendKeys.Send("{TAB}");
SendKeys.Send("{TAB}");
SendKeys.Send("{ENTER}");
Thread.Sleep(1000);
}
catch (Exception ex)
{
}
}
Another way to save is by commanding to the Chrome to save to the disk instead opening to the Page.
Below is the way to do:
ChromeOptions chromeOptions = new ChromeOptions();
// this will make automatically download to the default folder.
chromeOptions.AddUserProfilePreference("plugins.always_open_pdf_externally", true);
ChromeDriverService chromeDriverService = ChromeDriverService.CreateDefaultService();
chromeDriver = new ChromeDriver(chromeDriverService, chromeOptions);
var downloadsPath = KnownFolders.Downloads.Path;
var generatedFilePngs = Directory.GetFiles(downloadsPath, string.Format("{0}*.pdf", "TheNameOfYourPDF"));
You can directly send the request to the url without Selenium involved and get the byte array with content of PDF file. After that you can read file content using some PDF library (looks like ITextSharp is popular).
Inside Chrome browser all the dialog popups are html pages so you can click on them using Selenium.
In your case you can navigate to a page, simulate Ctrl + P keyboard button press, switch to print dialog window, click Change button to change the printer, click Save to PDF, click Save button and when "Save As" box is shown - simulate Enter keyboard button press to actually save the file.
I don't do C#, but here is how that looks like in Java, in fact I have tested it and it actually works:
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyPress(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_P);
robot.keyRelease(KeyEvent.VK_CONTROL);
// get current browser window handles and switch to window with handle that is last in the list
Set<String> windowHandles = driver.getWindowHandles();
for (String handle : windowHandles) {
driver.switchTo().window(handle);
}
driver.findElement(By.xpath("//button[contains(text(), 'Change')]")).click();
driver.findElement(By.xpath("//span[contains(text(), 'Save as PDF')]")).click();
driver.findElement(By.xpath("//button[contains(text(), 'Save')]")).click();
// you might need to add waiter here that waits a second, since script is too fast
// and needs to wait for save dialog box to be shown
robot.keyPress(KeyEvent.VK_ENTER);
I was trying to create (stream) and download a html file on the client in asp.net using Http Response.
Went through many related posts here but nothing really helped.
After spending almost over two days, I stumbled upon a solution.
However, would now want to understand the reason, why it failed earlier.
Here is the story:
Please consider the following ASP.net codebehind handler..
protected void UploadButton_Click(object sender, EventArgs e)
{
if (FileUploadControl.HasFile)
{
try
{
if (FileUploadControl.PostedFile.ContentType == MIMEAssistant.GetMIMEType(".xls"))
{
string filename = "log.htm";
string logContent = "This is a test log..";
// Some upload processing..
// Send log file for download
Response.Clear();
Response.ContentType = MIMEAssistant.GetMIMEType(filename);
Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename);
using (StreamWriter writer = new StreamWriter(Response.OutputStream, Encoding.ASCII))
{
writer.Write(logContent);
}
//Response.OutputStream.Write(buf1, 0, buf1.Length);
HttpContext.Current.ApplicationInstance.CompleteRequest();
Response.End();
}
else
StatusLabel.Text = "Upload status: Only .xls files are accepted!";
}
catch (Exception ex)
{
StatusLabel.Text = "Upload status: The file could not be uploaded. The following error occured: " + ex.Message;
}
}
}
Nothing really helped to make IE download the file and save it from getting stuck.
In the end, extracting the code under "// Send log file for download" from innermost to outermost in the function resolved the issue.
EDIT: Facing the issue again even after removing the culprits explained below..
Please help me understand why?
Note: In the code above, the statement Response.End() threw an exception that read :
[System.Threading.ThreadAbortException] = {Unable to evaluate
expression because the code is optimized or a native frame is on top
of the call stack.}
More info:
After further investigation and creating a sample application, I found that putting the download code inside the following code causes the issue:
if (FileUploadControl.HasFile)
{
try
{
this.HtmlLogDownload();
}
catch (Exception ex)
{
throw ex;
}
}
It works fine if I remove:
if (FileUploadControl.HasFile)
Here is the webform code too:
<form id="form1" runat="server">
<asp:FileUpload ID="FileUploadControl" runat="server" />
<asp:Button runat="server" ID="UploadButton" Text="Upload" OnClick="UploadButton_Click" />
<div>
</div>
</form>
Edit: The above works in Chrome and Mozilla. Fails in IE 11
I noticed IE11 returns an uploaded .png image as: "application/png" when checking it like this:
LabelStatus.Text = "Ongeldig afbeeldingstype: " & FileUploadKleinLogo.PostedFile.ContentType
It used to be "image/png"
My guess is that that's whats causing the issue in IE11 and not FF or Chrome
I am attempting to set a HyperLink control's NavigateUrl path to a file, so that the user can click on the link and download the file. In my C# and ASPX code, the URL appears properly set, but clicking on the link causes nothing to happen; right-clicking on the link and attempting to save the link attempts to save download.htm.
Behind the scenes, I'm creating the file in the temp directory and moving it to an available location for download. This part works; I'm including it for reference.
private string MoveFile(string file_name, string file_path)
{
string tempdir = HttpContext.Current.Server.MapPath( ConfigurationManager.AppSettings["docs_folder"] );
string new_file_name = Path.Combine( tempdir, Path.GetFileName( file_name ) );
try
{
if (File.Exists( new_file_name ))
{
File.Delete( new_file_name );
}
File.Move( file_name, new_file_name );
}
catch (Exception e)
{
string message = e.Message;
}
return new_file_name;
}
And here's how I'm presently setting the URL:
string download_file = downloader.DownloadFiles(); //Ultimately returns the path from the MoveFile method
hl_download.NavigateUrl = "file:///" + HttpUtility.UrlPathEncode( download_file ).Replace("\\","//");
hl_download.Visible = true;
My output looks like:
file:///C://users//codes%20with%20hammer//documents//visual%20studio%202012//Projects//Download%20File//Download%20File//Archive_to_download.zip
When I drop this URL directly into the browser, the file properly downloads. So why doesn't it work on the hyperlink?
I also tried setting the property on a static hyperlink. Same result. For comparison:
<asp:HyperLink ID="HyperLink1" runat="server" Visible="True" NavigateUrl="file:///C:/users/codes%20with%20hammer/documents/visual%20studio%202012/Projects/Download%20File//Download%20File//Archive_to_download.zip">click me</asp:HyperLink>
Revised
My ASHX page has the following code in ProcessRequest:
context.Response.Clear();
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader( "Content-Disposition", "attachment; filename=" + Path.GetFileName( download_file ));
context.Response.WriteFile( context.Server.MapPath( download_file ) );
context.Response.End();
Perhaps I should move this into my code-behind file?
Warning - insecure code ahead, do not use. For demo only.
Because you are making an HttpHandler (as per the comments) this is how you would set the NavigateUrl:
string download_file = downloader.DownloadFiles(); //Ultimately returns the path from the MoveFile method
hl_download.NavigateUrl = "~/Handler.ashx?file="+download_file; //simply append the path
hl_download.Visible = true;
Now, the problem is that the value of download_file will be the actual physical path on the server. If you blindly take the value and use it to read the file from your file system, a hacker can use the same technique to download ANY file from your server, at least, within your application folder.
This is somewhat more secure and may be okay to use depending on your scenario
If you decide to go with the HttpHandler option, you are going to have to create some sort of unique token whereby you associate the token to the physical path to the file on disk. If this is a hyperlink that only needs to be generated once and for the life of the session, you can do something like this:
string token = System.Guid.NewGuid().ToString();
Session[token]=download_file; //put the token in the Session dictionary
hl_download.NavigateUrl = "~/Handler.ashx?file="+token;
hl_download.Visible = true;
Now, on the HttpHandler you can simply do:
string file = Session[Request.QueryString["file"]];
if (file!=null)
{
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader(string.Format("Content-Disposition", "attachment; filename={0}",Path.GetFileName(file)));
Response.WriteFile(Server.MapPath(file));
Response.End();
}
In order to be able to access the Session in your handler, you also have to implement IReadOnlySessionState
Something like this (full code, untested):
public class Handler : IHttpHandler, IReadOnlySessionState
{
public bool IsReusable { get { return true; } }
public void ProcessRequest(HttpContext ctx)
{
string file = ctx.Session[Request.QueryString["file"]];
if (file!=null)
{
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader(string.Format("Content-Disposition", "attachment; filename={0}",Path.GetFileName(file)));
Response.WriteFile(Server.MapPath(file));
Response.End();
}
}
}
Of course, the hyperlink is only valid while the Session is still active. If you need to maintain the hyperlink forever, you need to implement this entirely different.
This is more secure because the chances of the token not being unique are very very slim. Also because it only stores the token in the Session, so if another user manages to "guess" a token or try a brute-force approach, he still won't get anything since the value simply is not on his Session but on someone else's.
Finally got this to work. I used a relative path, ./Archive_to_download.zip. I have documented the ASHX method for the next sprint.
lb.NavigateUrl = "~/Picture/" + files[i].Name;
I am making the users download a file on an anchor tag click. On its onclick event, i have used __doPostBack to partial post back the page to return the file which is downloadable by the user.
Now the problem i am facing is, that when the file is not found, the page reloads and the ajax calls are not set. So, in short, when the browser is expecting a response after _doPostBack function, and does not get one, it reloads the page but $.ajax methods do not run. What am i missing? Should I do something with the response? or is there any way that the response can be cancelled? Please help.
The anchor tag is, for instance
<a onclick="javascript:__doPostBack('AnnouncementAttachmentDownload','Ch 7 -Software Design2010.doc')">Ch 7 -Software Design2010.doc</a>
The server side code is
protected void Page_Load(object sender, EventArgs e)
{
SetPageTitles(ModuleNames.NotSpecified, null, false, true, true, false);
if (this.Request.Params["__EVENTTARGET"] == "AnnouncementAttachmentDownload")
{
string FileName = this.Request.Params["__EVENTARGUMENT"].ToString();
string destinationPath = Server.MapPath("~/" + System.Web.Configuration.WebConfigurationManager.AppSettings["AnnouncementAttachmentsPath"]).ToString() + "\\";
if (System.IO.File.Exists(destinationPath + FileName))
{
Response.AppendHeader("content-disposition", "attachment; filename=" + FileName);
Response.TransmitFile(destinationPath + FileName);
Response.End();
}
else
{
ClientScript.RegisterClientScriptBlock(this.GetType(), "NewScript", "alert('The requested file could not be found, please contact portal.production.support');", true);\\DOESNT WORK
}
}
}
The line in the else part, it just shows the message but the page loads after that too.
On the file not being found, i used Responce.Redirect to redirect it to the current page again, before that I stored a bool in a session variable, and on pageload i checked the session variable if it contained some value and then showed the message. Also, i cleared the session too on in the above if expression.
I wrote a program to download files from a website by using WebClient.DownloadFile().
public static void downWeb()
{
WebClient myWebClient = new WebClient();
path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
if (add() == 1)
{
Console.WriteLine("Response is " + add());
Console.WriteLine("Downloading File = " + dynFileName + "....");
myWebClient.DownloadFile(fullAddress, (path + dynFileName));
}
}
public static int add()
{
string url = fullAddress;
WebRequest webRequest = WebRequest.Create(url);
WebResponse webResponse;
try
{
webResponse = webRequest.GetResponse();
}
catch
{
return 0;
}
return 1;
}
downWeb() is a function to be called in the Main() function.
add() is a function that tests the availability of the file on server. If response is positive, it returns value "1".
fullAddress = address from where the files has to downloaded. It's changing every time before calling this function in a loop present in Main().
When I start my application, I ask the user to:
1) Enter URL to be downloaded i.e. www.1234.com\samplefiles\pg-1.pdf
2) Number of pages to be downloaded (By changing the above filename no. in a loop as rest of the url is same on server)
Now my problem is when I am downloading files, first file downloads PERFECTLY, but the second download is never finished. It says "REQUEST TIMED OUT", and my application closes.
I don't know what's happening here.
How can this be solved?
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.getresponse.aspx
You must call the Close method to close the stream and release the connection. Failure to do so may cause your application to run out of connections.
Your problem likely is related to the fact that you do not dispose of your connections. You should make sure that you don't leak them.