How to intercept when user click on a link in a webbrowser - c#

I'm trying to intercept tapping on a link in a WebBrowser control.
My HTML page contains custom links, for some starting with shared:// I'd like to intercept when the user tap on it.
On iPhone I would use the webView:shouldStartLoadWithRequest:navigationType: method, and look at the URL that is selected.
I haven't managed to reproduce a similar behaviour with Silverlight for Windows Phone.
I do something like:
{
webBrowser1.Navigating += new EventHandler<NavigatingEventArgs>(webBrowser1_Navigating);
}
void webBrowser1_Navigating(object sender, NavigatingEventArgs e)
{
string scheme = null;
try
{
scheme = e.Uri.Scheme; // <- this is throwing an exception here
}
catch
{
}
if (scheme == null || scheme == "file")
return;
// Not going to follow any other link
e.Cancel = true;
if (scheme == "shared")
{
}
But I guess an exception when reading some properties of the Uri, when it's a standard Uri with a default file:// URL
Additionally, the Navigating event isn't even triggered for links starting with shared://
Now that I'm able to capture tapping on a shared:// I do not care much, but at least I'd like to be able to retrieve the URL we're going to navigate to, and cancel the default operation for a particular URL.
Any ideas what's going on?
Thanks
Edit:
It turned out that the problem is that the Navigating event is only generated for the following links: file://, http:// or mailto://
The scheme attributes of the Uri is only available for the http:// and mailto:// links
so what I did in the end is replace the shared:// link with http://shared/blah ... And I look at the URL... This works for my purpose. I can now have links that have a different action (like opening an extra window) depending on the links in the html.

Here is my final code, in case this is useful for someone in the future:
For an about screen, I use an html file displayed in a WebBrowser component.
The about page has a "tell your friend about this app" link as well as links to external web site.
It also has local subpages.
Local sub-pages are linked to using a file:// link. Those can be navigated within the WebBrowser component.
External links are opened externally with Internet Explorer.
Tell your friend link is made of a http://shared link, that opens an email with a pre-set subject and body. Unfortunately, no other scheme than the standard ones are usable as they do not trigger a Navigating event
There's also a support link which is a mailto:// link and opens an EmailComposeTask
void webBrowser1_Navigating(object sender, NavigatingEventArgs e)
{
String scheme = null;
try
{
scheme = e.Uri.Scheme;
}
catch
{
}
if (scheme == null || scheme == "file")
return;
// Not going to follow any other link
e.Cancel = true;
if (scheme == "http")
{
// Check if it's the "shared" URL
if (e.Uri.Host == "shared")
{
// Start email
EmailComposeTask emailComposeTask = new EmailComposeTask();
emailComposeTask.Subject = "Sharing an app with you";
emailComposeTask.Body = "You may like this app...";
emailComposeTask.Show();
}
else
{
// start it in Internet Explorer
WebBrowserTask webBrowserTask = new WebBrowserTask();
webBrowserTask.Uri = new Uri(e.Uri.AbsoluteUri);
webBrowserTask.Show();
}
}
if (scheme == "mailto")
{
EmailComposeTask emailComposeTask = new EmailComposeTask();
emailComposeTask.To = e.Uri.AbsoluteUri;
emailComposeTask.Show();
}
}

Related

C# Unable to login with WebBrowser

I am newbie to C#. I need help to be able to login the webpage and read some data.
After googling, I tried to find below code and other resources but in all cases, I can only get the html source of the login page but not other pages source data.
I need to traverse to the homepage first.
Then, I need to traverse
to "Port Status" and read some useful data. To inform data is stored in the
frames. How can I read data from the frames ?
Adding more info
1) view-source:http://192.168.0.239/homepage.html, which calls script as shown below
getSubTree('Management');
2) The above call hits the content in java script file (http://192.168.0.239/frame.js)
case "Management":
str += OneNodeLink("lv1", "Switch Information", "/iss/specific/sysInfo.html?Gambit="+GAMBIT);
str += OneNodeLink("lv1", "Port Status", "/iss/specific/port_settings.html?Gambit="+GAMBIT);
document.getElementById("treeFrame").innerHTML = str;
3) The above code executes this file "view-source:http://192.168.0.239/iss/specific/port_settings.html?Gambit=pisfgagehesfhjikojngqcabdfkjeeffmpkhfckm" and gets "Port Status"
My requirement is to read the "Port Status" received which is from the frames data. Hope I am able to make it clear. Let me know if you need more info to help.
Link has screenshots and html source files : https://www.dropbox.com/sh/oml3tk75tf1lu5c/AADuGtbZci3gnyOQ2AE8IYwua?dl=0
Thanks a lot in advance
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WebBrowserWithoutAForm
{
class Program
{
private static bool completed = false;
private static WebBrowser wb;
[STAThread]
static void Main(string[] args)
{
wb = new WebBrowser();
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
string postData = string.Format("LoginPassword={0}&login=Login", "password");
ASCIIEncoding enc = new ASCIIEncoding();
wb.Navigate("http://192.168.0.239", "", enc.GetBytes(postData), "Content-Type: application/x-www-form-urlencoded\r\n");
//wb.Navigate("http://192.168.0.239");
while (!completed)
{
Application.DoEvents();
Thread.Sleep(100);
}
Console.Write("\n\nDone with it!\n\n");
Console.ReadLine();
}
static void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//Console.WriteLine(wb.Document.Body.InnerHtml);
completed = true;
Thread.Sleep(1000);
//*******HERE I NEED TO TRAVERSE TO THE HOME PAGE AND GET ITS SOURCE ******
wb.Navigate("http://192.168.0.239/homepage.html");
Console.WriteLine(wb.DocumentText);
}
}
}
I suggest you use selenium - my sample code of using Selenium to login facebook
I'm not gonna code for you but you could copy some part of my code though.
For the login page, I would do a GetElementById on the input for the login, and then set the value attribute. Then for the login button, if it's actually a button, I would trigger the click() event, otherwise if it is a form, then I would do a submit.
For port Status, you would again need to know the html of the home page and do a GetElementById on it and then trigger a click() event.
To put some code to these words it would look something like this:
var portStatus = this.webBrowser1.Document.GetElementById("portStatus");
portStatus.InvokeMember("click");
//this should give you access to DOM of the first frame on the page.
//if you have more than 1 then you will need to know which one.
var frameDoc= this.webBrowser1.Document.Window.Frames[0].Document;
//or
var frameDoc= this.webBrowser1.Document.Window.Frames["iframeid"].Document;;
var login = this.webBrowser1.Document.GetElementById("Login");
login.SetAttribute("Value", "password");
var loginButton = this.webBrowser1.Document.GetElementById("LoginButton");
loginButton.InvokeMember("click");
//or if the login button is a form then submit the form
HtmlElement form = webBrowser1.Document.GetElementById("FormID");
if (form != null)
form.InvokeMember("submit");
Since you didn't provide the HTML of the homepage, The Id's used here would have to be replaced by the actual Ids of the page. And you would replace "password" with whatever your actual password is here.
I hope this helps, if you need some explanation let me know.
Also see this for working with frames

Get response from server C#

I'm trying to submit a from using c# to a website and am trying to get the response from the server as a message box after the data is sent. the website does redirect to another page to show an output.
What happens so far is the data is not submitted until I click OK on the message box that is displaying the data before it is send not after.
WebBrowser browser = new WebBrowser();
string target = "http://www.awebsite.com";
browser.Navigate(target);
browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(XYZ);
}
}
private void XYZ(object sender, WebBrowserDocumentCompletedEventArgs e) // fail was here.
{
WebBrowser b = (WebBrowser)sender;
string text = richTextBox1.Text.ToString();
if (text == null)
{
MessageBox.Show("the messgae was empty");
}
b.Document.GetElementById("idmsg").InnerText = richTextBox1.Text.ToUpper().ToString();
b.Document.GetElementById("idpassw").InnerText = ".....";
b.Document.GetElementById("idpagers").InnerText = id;
b.Document.GetElementById("Send").InvokeMember("click");
// allow server response time
System.Threading.Thread.Sleep(5000);
string output = b.Document.Body.OuterText.ToString();
MessageBox.Show(output);
}
I'v also tried adding another Document complete with the //allow server response time code but again did'nt send till OK was pressed.
what am I doing wrong?
You do it totally wrong. Never rely on the.Sleep(...). C# provides rich enough async environment, namely Task DoAsync(...) which is to be used somewhat like await DoAsync(). This guarantees that no code going below the DoAsync() would ever be executed unless the async operation either completed successfully, either failed with error. As such, by the time you'll get to the last MessageBox.Show(...), all the data would be there, displayed properly as expected.

Grabbing Dropbox access token on Windows Form using Dropbox API

I have done a class which already works with the Dropbox API uploading files, downloading, deleting and so on. It has been working quite well since I was just using my own access token, but I need to register other users and a single but "big" problem appeared: retrieving the access token.
1.- Redirect URI? I'm starting to doubt why do I need this. I finally used this URI (https://www.dropbox.com/1/oauth2/redirect_receiver) because "The redirect URI you use doesn't really matter" Of course I included this one on my app config on Dropbox.
2.- I reach the user's account (I can see the user's count increased and I see the app has access to the user's account.
3.- I have a breakpoint on my code to inspect the variables in order to apply the DropboxOAuth2Helper.ParseTokenFragment but I have no success on there.
This is my code, but on the if before the try catch is where it gets stuck:
string AccessToken;
const string AppKey = "theOneAtmyAppConfigOnDropbox";
const string redirectUrl = "https://www.dropbox.com/1/oauth2/redirect_receiver";
string oauthUrl =
$#"https://www.dropbox.com/1/oauth2/authorize?response_type=token&redirect_uri={redirectUrl}&client_id={AppKey}";
private string oauth2State;
private bool Result;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Start(AppKey, webBrowser1);
webBrowser1.Navigating += Browser_Navigating;
}
private void Start(string appKey, WebBrowser w)
{
this.oauth2State = Guid.NewGuid().ToString("N");
Uri authorizeUri = DropboxOAuth2Helper.GetAuthorizeUri(OauthResponseType.Token, appKey, redirectUrl, state: oauth2State);
w.Navigate(authorizeUri);
}
private void Browser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
if (!e.Url.ToString().StartsWith(redirectUrl, StringComparison.InvariantCultureIgnoreCase))
{
// we need to ignore all navigation that isn't to the redirect uri.
return;
}
try
{
OAuth2Response result = DropboxOAuth2Helper.ParseTokenFragment(e.Url);
if (result.State != this.oauth2State)
{
// The state in the response doesn't match the state in the request.
return;
}
this.AccessToken = result.AccessToken;
this.Result = true;
}
catch (ArgumentException)
{
// There was an error in the URI passed to ParseTokenFragment
}
finally
{
e.Cancel = true;
this.Close();
}
}
I've been fighting against this for hours and I'm starting to see the things a little cloudy at this point.
This is the tutorial I used, but I'm not moving forward. I would really appreciate any help!
EDIT: I finally made some steps forward. I changed the line which contains
Uri authorizeUri2 = DropboxOAuth2Helper.GetAuthorizeUri(appKey);
Now I'm showing the generated access token on the WebClient! Bad part comes when trying to get it (it gets inside the if) and it gets generated every time I ask the user for permission, so it gets overwrited.
EDIT 2: I noted the token I get generated on the browser is somehow malformed. I try to manually change it hardcored when I'm debugging and I get an exception when an AuthException when creating the DropboxClient object :( What the hell!
As Greg stated, the solution was using the event Browser_Navigated. Looks like the version of the embedded IE my Visual Studio (2015) uses didn't notice that if it's a redirect, it won't launch the event BrowserNavigating.

Stop process if webBrowser control hangs

I am using the WebBrowser control.
This works fine most of the time however wehn navigating to a new page or waiting for a new page to load can sometimes hangs.
Is there a way to catch this? i.e. if the page is failing to navigate or load after a certain amount of time then kill the process?
I am using the - webBrowser1_DocumentCompleted event to pick up ertain behaviours when the page loads/navigates as expected however not sure how to catch if a page is hanging??
Maby you should try to implement some kind of timeout logic? There are quite many samples in web about this. F.e. this one
Also you might be interested in this event of WebBrowserControl ProgressChanged
This is due to that webbrowser component is very basic model of internet explorer, and it get stuck at ajax pages. You can fix this problem explicitly to use latest version of internet explorer... Using this code...
try
{
string installkey = #"SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
string entryLabel = "YourExe.exe";
string develop = "YourExe.vshost.exe";//This is for Visual Studio Debugging...
System.OperatingSystem osInfo = System.Environment.OSVersion;
string version = osInfo.Version.Major.ToString() + '.' + osInfo.Version.Minor.ToString();
uint editFlag = (uint)((version == "6.2") ? 0x2710 : 0x2328); // 6.2 = Windows 8 and therefore IE10
Microsoft.Win32.RegistryKey existingSubKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(installkey, false); // readonly key
if (existingSubKey.GetValue(entryLabel) == null)
{
existingSubKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(installkey, true); // writable key
existingSubKey.SetValue(entryLabel, unchecked((int)editFlag), Microsoft.Win32.RegistryValueKind.DWord);
}
if (existingSubKey.GetValue(develop) == null)
{
existingSubKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(installkey, true); // writable key
existingSubKey.SetValue(develop, unchecked((int)editFlag), Microsoft.Win32.RegistryValueKind.DWord);
}
}
catch
{
MessageBox.Show("You Don't Have Admin Previlege to Overwrite System Settings");
}
}
Right Click Both your Exe. And vshost.exe and Run as Administrator To Update Registry for this Application....

Inserting Google Maps into my Web Page in asp.net

I am creating a web app. where I want be able to incorporate Google Maps into 1 of my pages.
From what I have read in other places, the easiest think is to place a web browser onto the form but there is no 'Web Browser' in the tool-box.
What I am trying to do is to insert a location into a textbox(ie. London) and insert a type of sport(ieCycling) and the resultant map shows up. Is there any other way in doing this in C# other than using the web browser tool.
Here is my code:
protected void btnSearch_Click(object sender, EventArgs e)
{
string sport = txtSport.Text;
string location = txtLocation.Text;
try
{
StringBuilder queryAddrress = new StringBuilder();
queryAddrress.Append("https://maps.google.ie/");
if (sport != string.Empty)
{
queryAddrress.Append(sport+","+"+");
}
if (location != string.Empty)
{
queryAddrress.Append(location + "," + "+");
}
Panel1.Navigate(queryAddrress.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(),"Error");
}
} protected void btnSearch_Click(object sender, EventArgs e)
{
string sport = txtSport.Text;
string location = txtLocation.Text;
try
{
StringBuilder queryAddrress = new StringBuilder();
queryAddrress.Append("https://maps.google.ie/");
if (sport != string.Empty)
{
queryAddrress.Append(sport+","+"+");
}
if (location != string.Empty)
{
queryAddrress.Append(location + "," + "+");
}
Panel1.Navigate(queryAddrress.ToString());
}
I tried to put the address into a panel but this is clearly wrong. Any help would be greatly appreciated!
It seems like you are very confused and mixing ASP.NET Web Forms with Windows Forms.
Specifically, MessageBox.Show() would open a Windows message box, not a browser window. And it would happen on the server side for whatever user your web server runs as. Probably not the desired intention. Also, you can't "put a web browser" onto a page. There is a WebBrowser control for Windows Forms, which embeds a minified version of Internet Explorer into a Windows application. But again, probably not what you want.
ASP.NET can be used as if it were just a normal HTML site. So find some Google Maps tutorials for HTML and follow those.

Categories

Resources