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.
Related
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
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.
I have a site where I'm trying to deliver files via WriteFile and they work fine in Chrome and Firefox, but in IE I have to hit "Retry" once or twice to actually make the file download.
Here is the code:
public class DownloadHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var r = context.Response;
r.Clear();
r.ClearContent();
r.ContentType = "application/octet-stream";
string path = "";
try
{
if (HttpContext.Current.Request.QueryString["n"] != null)
{
var file = HttpContext.Current.Request.QueryString["n"].ToString();
var type = HttpContext.Current.Request.QueryString["t"].ToString();
r.AddHeader("Content-Disposition", "attachment; filename=" + file.Substring(file.IndexOf('_')+1));
string folder = "";
switch (type.ToLower())
{
case "public":
folder = ConfigurationManager.AppSettings["BCD_PublicDocsLoc"];
break;
case "private":
folder = ConfigurationManager.AppSettings["BCD_PrivateDocsLoc"];
break;
case "internal":
folder = ConfigurationManager.AppSettings["BCD_InternalDocsLoc"];
break;
}
path = folder + "/" + file;
r.WriteFile(path);
r.Flush();
r.Close();
r.End();
}
}
catch (Exception ex)
{
r.Flush();
r.Close();
r.End();
context.Response.Redirect("Error.aspx?err=301");
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
If anyone has any advice as to why this is happening, it would be greatly appreciated. Thanks!
Try substituting the HttpResponse's Close() and End() calls with HttpApplication.CompleteRequest().
Read here why, there are examples too.
Also, this solution was suggested here(in the first answer) for a situation similar to yours.
As was hinted that a small explanation in this post would be convenient, due to the possibility of the links going dead in the future, here it goes:
In short: IE seems to have problems with the HttpResponse.Close and HttpResponse.End methods. Aside of that, anyways, Microsoft recommends in most cases the use of HttpApplication.CompleteRequest over the former two, because:
-HttpResponse.Close() terminates the connection abruptly, dropping buffered data and is not intended for normal HTTP use in which a response to the client is desired
-HttpResponse.End() exists for compatibility reasons with the older ASP technology. It calls the EndRequest event directly and no further code after the End call is executed which is inconvenient in many cases
-HttpApplication.CompleteRequest(): also executes the EndRequest event and it does allow the execution of the code that following the CompleteRequest call, which makes it more appropriate to handle most situations.
Just a hunch but it sounds like an I.E. caching issue to me...
if I.E is set to automatically check for newer pages 'every time i go to the website.' (in [tools\internet options\general\ browsing history\settings]) then you wont have a cache issue.
Like I say, only a hunch, but give it a whirl.
If you want to get around this [*1], add a guid to your Query string.[*2]
[*1] The cache setting is a user by user setting, you can never pre-empt the users settings, so work with them instead
[*2] The nocache value is always different, the browser will never have a cached version to go to.
I use something like this...
protected void Page_PreRender(object sender, EventArgs e)
{
if (HttpContext.Current.Request.QueryString["FirstRun"] == "1")
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.Url.Query);
nvc.Remove("FirstRun");
string url = Request.Url.AbsolutePath;
for (int i = 0; i < nvc.Count; i++)
url += string.Format("{0}{1}={2}", (i == 0 ? "?" : "&"), nvc.Keys[i], nvc[i]);
Response.Redirect(string.Format("{1}&NoCache={0}",System.Guid.NewGuid().ToString().Replace("-",""),url));
}
}
Any links/redirects to this page need ?FirstRun=1 (or &FirstRun=1) appended to the querystring. The page reload cycles itself once adding a &noCache value to the querystring.
Note:
Because you added FirstRun=1, it will always execute twice serverside, but appear like a single load to your user, and the browser.
If you don't add FirstRun=1, it will behave like a normal request as it never gets into the condition.
WE have an intranet webpage which is used to display information to works on monitors around our site. This webpage is automatically refreshed every 15 seconds.
All this works find, until the Database server has a problem and the webpage and no longer get a connection, and we get an error back normally an HTTP 500 error.
My solution to this has been to write a C# application that checks the HTTP status of the webpage, and if a HTTP 500 is found to close the browser and then reopen it again and display the webpage.
This application is using a timer event set to ever 30 seconds.
The problem I am having is my C# application does not always pick up the 500 error, or any other error that may cause the webpage to stop refreshing.
Below is the code I have written to try and check for the error(s)
public static void Check_Process()
{
Console.Write("checking started at {0}" + Environment.NewLine, DateTime.Now);
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(txt_url);
response = (HttpWebResponse)request.GetResponse();
// Read the error stream first and then wait.
string error = someProcess.StandardError.ReadToEnd();
Console.Write(error);
}
catch (WebException e)
{
if (e.Status == WebExceptionStatus.ProtocolError)
{
response = (HttpWebResponse)e.Response;
if ((int)response.StatusCode == 500)
{
Console.Write((int)response.StatusCode + " error found at {0}" + Environment.NewLine, DateTime.Now);
Close_webpage();
Start_webpage();
}
else if (response.StatusCode != HttpStatusCode.OK)
{
Console.Write((int)response.StatusCode + " error found at {0}" + Environment.NewLine, DateTime.Now);
Close_webpage();
Start_webpage();
}
}
}
}
The webpage is currently loaded from within the application using
public static void Start_webpage()
{
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.FileName = "IExplore.exe";
startInfo.Arguments = txt_url;
someProcess = Process.Start(startInfo);
}
Hoping someone can point out where I have gone wrong, or a better way of doing this, as currently we are have to manually refresh/reload the webpage.
Do you do a complete page reload ?
How about you use ajax call instead ? You can put that in setInterval/setTimeout, and then process successful/failed responses - should make it resistant to service failures, and more user-friendly.
And yes, you probably should eliminate 500. Try/catch{msg("OMG, database is not accessible!")} type of thing :)
Ah, and the issue with your code could be the fact that your code checks database and its fine, but then the 500th user connects, and your page refresh fails.
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();
}
}