I'm using WebKitDotNet to simulate and automate a web browser. This is really nifty and works in most respects. However, when I try to implement this code, WebKit doesn't trigger a download:
WebKitBrowser _b = null;
private void button1_Click(object sender, EventArgs e)
{
_b = new WebKitBrowser();
_b.DownloadBegin += new FileDownloadBeginEventHandler(b_DownloadBegin);
_b.Error += new WebKitBrowserErrorEventHandler(_b_Error);
_b.AllowDownloads = true;
_b.Navigate("http://sourceforge.net/projects/webkitdotnet/files/WebKit%20.NET%200.x/0.5/WebKit.NET-0.5-bin-cairo.zip/download");
}
void _b_Error(object sender, WebKitBrowserErrorEventArgs e)
{
MessageBox.Show("error!");
}
void b_DownloadBegin(object sender, FileDownloadBeginEventArgs e)
{
MessageBox.Show("hi");
}
Neither the "Error" nor the "DownloadBegin" events fire. I would expect at least one of them to do so - is there a setting that I'm missing?
EDIT: I know this is an old question, but here's the update. When I wrote this question, I was trying to automate a process that required a human being - once per day - to log onto a website, provide credentials, and click a download link. We were hoping to be able to do this programmatically to relieve the monotony for the poor person tasked with doing this job.
Unfortunately, WebKitDotNet did not succeed in this task. Although, in a webkit based browser, you can click on the link and trigger a download, in the embedded WebKitDotNet clicking on the link did nothing. My guess is that something within WebKitDotNet lost the event. If anyone wants to test this, you can use the Sourceforge download link to test.
One of the guys on my team did eventually solve this problem by using an Internet Explorer automation tool called "IMacros". We selected this product because 1) We could guarantee that IE was installed on every computer that would run the program, and 2) IMacros could correctly receive the event from the website and trigger the file download.
On the Issue tracker there is a post date from March 24, 2011 in which is stated that download does not work yet:
https://github.com/webkitdotnet/webkitdotnet/issues/7
Since there are few issues in the tracker, it would have probably been marked as resolved if the feature was added meantime.
Related
I found myself at a very strange problem. In the application we are developing, there is a feature to send the mail from the app itself.
According to Xamarin recipes, the MFMailComposeViewController is the way to go for the Xamarin.ios.
https://developer.xamarin.com/recipes/ios/shared_resources/email/send_an_email/
As it seems there is a problem with just some of the devices, however the pattern is to me unclear.
While pressing the button "Send" or Cancel, the Finished delegate is called. This part should normally dismiss the MailViewController.
On some of the devices the behaviour is as expected, the Mail controller is removed from the screen and the underlying controller is displayed.
On some devices however, the mail controller stays on top, and the app is not responding anymore. The debugger does not show anything.
Did anybody face this issue so far? Could this be somehow solved? I was reading some of the similar behavior in obj-c or swift code, however their solution did not help me.
MFMailComposeViewController in Swift does not dismiss
This is my code:
private void OnSendMailClick(object sender, EventArgs e)
{
if (MFMailComposeViewController.CanSendMail)
{
string receiptText = trx.isReversed ?
Utilities.GetTransactionAndRefundReceipt(trx, manager) : Utilities.GetReceipt(trx, true);
var mailController = new MFMailComposeViewController();
mailController.SetSubject(String.Format("Receipt number: {0}", trx.STAN));
mailController.SetMessageBody(receiptText, true);
mailController.Finished += OnSendResult;
PresentViewController(mailController, true, null);
}
}
and the Finished delegate looks like this:
private void OnSendResult(object sender, MFComposeResultEventArgs e) => e.Controller.DismissViewController(true, null);
Edit
It turns out the problem is in the inheritance of the MFMalComposeViewController, which is inherited by UINavigationViewController.
As I am already using an underlying UINavigationcontroller this causes sometimes problems. As soon as I find a suitable solution I will post it here as an answer.
The problem was solved. It turns out, that the problem lied in the nuget package I was using.
https://github.com/jdehlin/Xamarin-Sidebar/
From the version 1.9.4 the behavior is easily reproducible with an iPhone device.
I wrote this little bit of C# code to test an implementation I intend to use for an internal tool at work. Much to my surprise, it functions exactly as I hoped but I do not understand why.
private void button1_Click(object sender, EventArgs e)
{
WebClient wc = new WebClient();
wc.DownloadFile("http://url censored", #"C:\Users\Dustin\Desktop\flashplayer.exe");
bool dlComplete = System.IO.File.Exists(#"C:\Users\Dustin\Desktop\flashplayer.exe");
if (dlComplete == true)
{
System.Diagnostics.Process.Start(#"C:\Users\Dustin\Desktop\flashplayer.exe");
}
else
{
System.Windows.Forms.MessageBox.Show("Something's jacked!");
}
}
When I press on button1, my machine downloads the Flash installer and then checks if the file exists (this is my roundabout way of avoiding event handlers which I have not learned to deal with yet), and continues on.
Why doesn't my computer check for the file's existence while the file is downloading? How does this wizard of a computer know to hold on a moment while the file download completes?
WebClient.DownloadFile is a Synchronous method in which downloads to a local data file.
As stated on the MSDN link here - "[t]his methods blocks while downloading the resource."
In other words, the process is waiting for completion (blocking the calling function), before returning control and execution to the thread.
This results in the wizardry you're experiencing with the application knowing when to check for the file's presence. I know magic can be ruined once you know the trick; however, I hope this ins't the case..
For reference, here's a way that would work the way you didn't expect, asynchronously.
var webClient = new WebClient())
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
webClient.DownloadFileAsync("http://www.server.com/file.txt", "C:\\file.txt");
In fact, there's a whole set of Asynchronous C# functions. It's worth reading up on if you're interested in getting into development.
https://msdn.microsoft.com/en-us/library/mt674882.aspx
Whenever I update my web app on IIS, any user who currently using it, will see the page be unresponsive and it won't work again until they refresh the browser. (The update process last for about 30 seconds)
I would like to show up a notification, such as a javascript alert, for user to know that the page is being udpated and please try to refresh the page after 30 seconds, etc.
I tried to catch the Exception in Global.ascx but no exception was thrown in this case.
Consider using app_offline.htm. It is a page that will cause clients to see your IIS app as being down. When you're through updating, just remove the page.
You could create a FileSystemWatcher in global.ascx then bubble up (update a js for instance) an exception when a file is updated. You could start with this:
using System.IO;
namespace WebApplication1
{
public class Global : System.Web.HttpApplication
{
FileSystemWatcher watcher;
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
watcher = new FileSystemWatcher(this.Context.Server.MapPath("/"));
watcher.Changed += new FileSystemEventHandler(watcher_Changed);
}
void watcher_Changed(object sender, FileSystemEventArgs e)
{
//set a value in js file
FileInfo jsFilesChanged = new FileInfo(Path.Combine(this.Context.Server.MapPath("/"), "scripts", "files_changed.js"));
using (StreamWriter jsWriter = (!jsFilesChanged.Exists) ? new StreamWriter(jsFilesChanged.Create()) : new StreamWriter(jsFilesChanged.FullName, false))
{
jsWriter.WriteLine("var changed_file = \"" + e.Name + "\";");
}
}
//.......
}
}
Then in client code include files_changed.js and create a periodic timeout call to check the var changed_file. Also, make sure watcher doesn't get garbage collected.
Some references:
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.aspx
http://www.developerfusion.com/article/84362/extending-filesystemwatcher-to-aspnet/
How the big boys do this:
You need to have a way of posting an alert on a page. Typically this is done by having a table in your database for these alerts. Basically you are just storing some text in there like "hey, the site is going down for maintenance between 8:00am and 8:01am"..
On each page load, you check that table and display any messages found in a conspicuous place (like the top).
Prior to pushing an update you add the alert, while giving them enough time to wrap up whatever it is that they are doing.
After the push is complete you clear out the alerts table.
Honestly the main issue you have is simply one of scheduling updates and communicating to the users what's about to happen. You want to do so in a way that isn't a surprise. That said, you might consider enabling the optimizeCompilations flag in order to try and speed up the compilation time of your website when it is first hit after pushing an update.
I'm trying to create GUI program that generates HTML invoices, and sends them for printing. I have this working. However, now I want to introduce threading.
I have a form with a BackgroundWorker. The Background worker runs this code:
#region BackGroundWorker
private void bg_htmlGeneration_DoWork(object sender, DoWorkEventArgs e)
{
//SOME MORE CODE..
foreach (XElement ele in Lib.GetInvoiceElement(inv, ico.Supplier))
{
PrintDocument(Lib.CreateHTMLFile());
}
}
#endregion
public void PrintDocument(string fileName)
{
var th = new Thread(() =>
{
WebBrowser webBrowserForPrinting = new WebBrowser();
webBrowserForPrinting.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(PrintDocumentHandler);
webBrowserForPrinting.Url = new Uri(fileName);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
public void PrintDocumentHandler(object sender, WebBrowserDocumentCompletedEventArgs e)
{
((WebBrowser)sender).Print();
((WebBrowser)sender).Dispose();
Application.ExitThread();
}
Everything runs through fine. However, the WebBrowser object refuses to print. There are no errors (that are obvious), the program finishes off with nothing sent to the printer. When I take away the threading, the program works again.
My knowledge of threading is weak, and I'm pretty much teaching myself - so presumably I'm misunderstanding how threading priority is set.
Here's How it should work:
User selects Invoice(s) on Main Form, chooses to print.
Background thread goes away and prints them while user continues on the program.
Any ideas would be appreciated.
Main problem with your code is WebBrowser wrong using.
WebBrowser supposed to be used for interactive web-browsing, during it user do some things in the internet. But in your case you are using WebBrowser just for the printing after downloading the html. This is wrong by two reasons:
Your code creates whole Windows Forms Control and not using even half of its functionality.
Your code tries to use the WinForms Control in the background thread, which leads to the unexpected behaviour.
BackgroundWorker class supposed to be used for
execute a time-consuming operation (like downloads and database transactions) in the background.
Much more:
You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.
Your code will fail in the background thread, because WinForms control is a user-interface object.
Just for the record, WebBrowser.Print method invokes native windows API, so you have no chance that this will work in background. From the disassembly code:
this.AxIWebBrowser2.ExecWB(NativeMethods.OLECMDID.OLECMDID_PRINT,
NativeMethods.OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER,
ref obj,
IntPtr.Zero);
So, my suggestion for your code is:
Remove usage of the WebBrowser class in the background. Use HttpWebRequest instead for downloading the web content.
Choose other way for the printing your downloaded content. Options are:
PrintDocument implementation (example for it is here).
Use MS Office classes for opening and printing your html-files (first parameter for the Print method is a Boolean Background, I think this can help you). As far as I know, even in 2010 this approach works well.
Check other questions about printing (here is a discussion of printing the images, but this is the same thing, I think).
PS: in the comments you've said that you may need the PDF from your html. I did this by C# by two ways:
Batching using the wkhtmltopdf
Using Microsoft Office Add-in: Microsoft Save as PDF or XPS.
This Add-in should be installed on the server, after that you can easily use MS Office classes for saving the output in the PDF format.
Some update here:
As we have an async/await and TPL options for the time-consuming operations, I don't recommend you to use the BackgroundWorker class anymore.
I created a ASP.NET Website with Visual Studio 2010 C#.
My program reads a config file to create some classes and display informations.
The config file is not included in the project (does not appear in the solution explorer). If I modify the file while my application is not running, and run it afterwards, it still reads the old version like it keep it in cache. I have to close Visual Studio for it to accept the changes.
My second problem is related to (if not caused by) my first problem. I am using FileSystemWatcher to see if the config file is modified while the application is running, but the Changed event is never called.
private string _configFilePath;
private FileSystemWatcher _watcher;
protected void Page_Load(object sender, EventArgs e)
{
//Gets the config file in the application's parent directory
string appPath = this.MapPath("~");
string[] split = appPath.Split('\\');
_configFilePath = appPath.Substring(0, appPath.Length - split[split.Length-1].Length);
Application.Add("watcher", new FileSystemWatcher(_configFilePath.Substring(0, _configFilePath.Length-1), "*.xml"));
_watcher = (FileSystemWatcher)Application["watcher"];
_watcher.NotifyFilter = NotifyFilters.FileName;
_watcher.Changed += new System.IO.FileSystemEventHandler(Watcher_Changed);
_configFilePath += "ProductsConfig.xml";
UpdateDisplay();
}
private void Watcher_Changed(object source, FileSystemEventArgs e)
{
UpdateDisplay();
}
How can I solve this?
Thank you
My second problem is related to (if not caused by) my first problem. I
am using FileSystemWatcher to see if the config file is modified while
the application is running, but the Changed event is never called.
It's never called because at that point the Thread that's servicing the request is already returned to the pool and the request has ended. The Watcher_Changed event will never fire.
You need to tackle this in a different manner, remember that HTTP is a "disconnected" protocol, after the request has been served, don't expect any of the page events to fire "automagically" when something happens on the server side that would notify all connected users.
One way to do this is via Ajax. You'd need to constantly "ask" the server whether there's new information or not and update the sections of the page that need to be updated as a result of the change on the server.
There are 2 problems here.
1. You never called _watcher.EnableRaisingEvents = true;
2. You try to go to the parent folder of your root folder, which might not be allowed.
/ Tibi