Here's my code:
delegate void del(string data);
public partial class CreateUser : System.Web.UI.Page
{
static string rfidkey;
SerialPort serialPort1;
//Timer timer1;
del MyDlg;
private delegate void SetTextDeleg(string text);
public CreateUser()
{
serialPort1 = new SerialPort();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
//
timer1 = new Timer();
timer1.Interval = 100;
timer1.Enabled = false;
timer1.Tick += new EventHandler<EventArgs>(timer1_Tick);
//
MyDlg = new del(Display);
}
void Display(string s)
{
txtRFIDKey.Text = s;
}
void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Data.s = serialPort1.ReadExisting();
//txtRFIDKey.Text = Data.s;
MyDlg.BeginInvoke(Data.s, null, null);
}
}
This cannot be done the way you are coding it. Basically, you are trying to treat your web page like a Windows application. You need to understand the the "code behind", the code you have written above, runs on one computer, and the web page, where the text field is, is displayed on another. And once the page construction code finishes running, the server can't change the page. You can use postbacks and Ajax from the web page to call back to the server, but even that might not help you with the code you trying to write.
To get a better understanding of the fundamentals of asp.net web page processing, start here: ASP.NET page life cycle explanation
Or, you can just code your page as an Application using Windows Forms, or WPF.
Related
Setup:
Win10 .NET 4.7.1/VS2017 .NET 4.5/ C#
Level:
Beginner/Intermediate/new to threading
Objective:
1: A selenium web automation class that is triggered by a timer class so that the web automation class can exchange data with a javascript site at specific times.
2: Should be possible to migrate solution from WebForms to .NET library (dll).
Problem:
Step 1. Timer class sends time event to method in Web class to login to internet site = working.
Step 2. Web automation class (WinForms/GUI) tries to retrieve data from the method that is triggered by timer class event = Exception: "Calling thread cannot access this object because a different thread owns it." (as translated from swe).
I admit I´m confused by the terminology in the area of threading that is new to me. Also, I understand some multithreading techniques are only valid for WinForms. Since my objective is to migrate the solution to a dll these are not an option for me. I´ve played around with Invoke(), but as I understand it´s limited to use in WinForms. Guidance is highly appreciated!
WEB AUTOMATION CLASS:
private EdgeDriver driver;
private SeleniumHelper helper;
private WebAutomationTimer timer;
private double account;
public double Account { get => this.account; set => this.account = value; }
public Form1()
{
InitializeComponent();
timer = new WebAutomationTimer(02, 36, 00, 02, 38, 00);
timer.OnLoginTime += Timer_OnLoginTime;
timer.OnLogoutTime += Timer_OnLogoutTime;
}
private void Timer_OnLoginTime()
{
Login();
}
private void Timer_OnLogoutTime()
{
Logout();
}
public bool Login()
{
try
{
// working login code
UpdateLabels();
}
catch (Exception e)
{
}
}
private void UpdateLabels()
{
// EXCEPTION !!!
lblAccount.Text = GetAccount();
// EXCEPTION !!!
}
TIMER CLASS:
class WebAutomationTimer
{
public event TimerEvent OnLoginTime;
public event TimerEvent OnLogoutTime;
//public event TimerEvent OnSecond;
private System.Timers.Timer timer;
private DateTime now;
private int loginHour;
private int loginMin;
private int loginSec;
private int logoutHour;
private int logoutMin;
private int logoutSec;
public WebAutomationTimer(int loginHour, int loginMin, int loginSec, int logoutHour, int logoutMin, int logoutSec)
{
timer = new System.Timers.Timer();
timer.Interval = 1000; // 1 sec
timer.Elapsed += Timer_Elapsed;
timer.Start();
this.loginHour = loginHour;
this.loginMin = loginMin;
this.loginSec = loginSec;
this.logoutHour = logoutHour;
this.logoutMin = logoutMin;
this.logoutSec = logoutSec;
}
// Each second event
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
now = DateTime.Now;
//OnSecond();
//login
if (now.Hour == loginHour && now.Minute == loginMin && now.Second == loginSec)
OnLoginTime();
//logout
if (now.Hour == logoutHour && now.Minute == logoutMin && now.Second == logoutSec)
OnLogoutTime();
}
}
}
When you want to update View's control from another Thread it must show you error. Because it is using by UI Thread. In this case you have to use SynchronizationContext class or you can send Delegate to the App.Current.Dispatcher.BeginInvoke(delegate must be here);
SynchronizationContext _context = SynchronizationContext.Current;
private void UpdateLabels()
{
_context.Post(x=>
{
lblAccount.Text = AccountBalance.ToString();
},null),
//...
}
Alternative of SynchronizationContext :
private void UpdateLabels()
{
var action = new Action(() =>
{
lblAccount.Text = AccountBalance.ToString();
});
App.Current.Dispatcher.BeginInvoke(action);
//...
}
Both of them are same.
UI thread adapted for keyboard event and mouse event.
When you App.Current.Dispatcher.BeginInvoke(delegate) you say to the UI Thread that
"execute this too".
In addition you can suppose UI Thread like this
while(!thisApplication.Ended)
{
wait for something to appear in message queue
Got something : what kind of this message?
Keyboard/Mouse message --> fire event handler
User BeginInvoke message --> execute delegate
User Invoke message --> execute delegate & post result
}
this error is beacuse of change lable text beacuse lable is in another thread you can use this code
lblAccount.Invoke(new EventHandler((s, ee) => { lblAccount.Text = AccountBalance.ToString(); }));
This solution is probably only valid in my case. OP can delete this question if it´s believed to be a duplicate.
The first objective with was an easy to develop/run/debug situation with a GUI. Setting properties causes no cross thread exception. Showing the properties in a MessageBox.Show() causes no exception either. Hence no cross thread issues to dodge in the development/GUI stage.
The second objective was to migrate to a dll, hence no need to interfere with a GUI thread.
/Thanks anyway
I get the following error on page_load:
c# no argument given that corresponds to the required formal parameter
Why is this?
protected void Page_Load(object sender, EventArgs e)
{
timerevent();
}
DataSet _dataSet = new DataSet();
private DataTable _dataTable;
string _sqlQuery = #"show slave status;";
string _sqlStop = #"stop slave;";
string _sqlStart = #"start slave;";
System.Timers.Timer mytimer = new System.Timers.Timer();
private void SetTimer()
{
mytimer.Elapsed += new ElapsedEventHandler(timerevent);
mytimer.Interval = 1000;
}
private void timerevent(object sender, ElapsedEventArgs e)
{
BindData();
}
public void BindData()
{
mytimer.Start();
}
Did you stop to consider the lifecycle of a Page? Think about it.
An instance of your Page class is created when an HTTP request comes in. Once the page has gone through all of its lifecycle events, an HTTP response is sent to the client. At that point, the Page instance will be destroyed. It will go away, taking any state stored in it (such as field containing a timer) with it.
For these reasons, the approach you're trying simply will not work.
If you want to update the client's DOM update every 5 minutes, you'll either have to have some client side code (JavaScript) that contains a timer and initiates a new HTTP request, or use tech like web sockets (SignalR) to push changes. If you do choose a SignalR approach, you can have a separate service with scheduling functionality (perhaps using Hangfire or Quartz) to initiate the push.
I am desperately trying to implement a "Session Inactivity Timeout" for an IT security policy.
sss
However, my inactivity reset logic isn't firing. What am I doing wrong? I can't attach a breakpoint due to Visual Studio crashing on attaching to Silverlight binary. I am wondering if the problem is something very subtle, such as at the time the App constructor is called, there is no "current RootVisual" yet. Tagging with #WPF as well since #Silverlight is dead/obsolescent. Sample code below.
namespace TestApp
{
public partial class App : Application
{
System.Windows.Threading.DispatcherTimer sessionTimer = new System.Windows.Threading.DispatcherTimer();
public App()
{
ResetSessionTimer();
this.RootVisual.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(rootVisual_MouseLeftButtonDown), true);
//this.RootVisual.MouseLeftButtonDown += rootVisual_MouseLeftButtonDown;
InitializeComponent();
}
private void ResetSessionTimer()
{
sessionTimer.Stop();
sessionTimer.Tick -= sessionTimer_Tick;
sessionTimer = new System.Windows.Threading.DispatcherTimer();
sessionTimer.Interval = TimeSpan.FromMinutes(1);
sessionTimer.Tick += sessionTimer_Tick;
sessionTimer.Start();
}
private void sessionTimer_Tick(object sender, EventArgs e)
{
System.Windows.Browser.HtmlPage.Document.GetElementById("LogoutButton").Invoke("click", null);
}
private void rootVisual_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// added this alert to see if code is even firing.
System.Windows.Browser.HtmlPage.Window.Invoke("alert", "hello, world");
ResetSessionTimer();
e.Handled = false;
}
}
}
I figured this out - somewhere in the code, the previous developer was overriding the this.RootVisual element with a new MainPage() in order to enable their homegrown dependency injection / MVVM architecture. I moved the logic from the App() constructor to right after this assignment operator, and it works like magic.
I want to get html code from website. In Browser I usually can just click on ‘View Page Source’ in context menu or something similar. But how can I automatized it? I’ve tried it with WebBrowser class but sometimes it doesn’t work. I am not web developer so I don’t really know if my approach at least make sense. I think main problem is that I sometimes get html where not all code was executed. Hence it is uncompleted. I have problem with e.g. this site: http://www.sreality.cz/en/search/for-sale/praha
My code (I’ve tried to make it small but runnable on its own):
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WebBrowserForm
{
internal static class Program
{
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
for (int i = 0; i < 10; i++)
{
Form1 f = new Form1();
f.ShowDialog();
}
// Now I can check Form1.List and see that some html is final and some is not
}
}
public class Form1 : Form
{
public static List<string> List = new List<string>();
private const string Url = "http://www.sreality.cz/en/search/for-sale/praha";
private System.Windows.Forms.WebBrowser webBrowser1;
public Form1()
{
this.webBrowser1 = new System.Windows.Forms.WebBrowser();
this.SuspendLayout();
this.webBrowser1.Dock = System.Windows.Forms.DockStyle.Fill;
this.webBrowser1.Name = "webBrowser1";
this.webBrowser1.TabIndex = 0;
this.ResumeLayout(false);
Load += new EventHandler(Form1_Load);
this.webBrowser1.ObjectForScripting = new MyScript();
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate(Url);
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
// Final html for 99% of web pages, but unfortunately not for all
string tst = webBrowser1.Document.GetElementsByTagName("HTML")[0].OuterHtml;
webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
Application.DoEvents();
webBrowser1.Navigate("javascript: window.external.CallServerSideCode();");
Application.DoEvents();
}
}
[ComVisible(true)]
public class MyScript
{
public void CallServerSideCode()
{
HtmlDocument doc = ((Form1)Application.OpenForms[0]).webBrowser1.Document;
string renderedHtml = doc.GetElementsByTagName("HTML")[0].OuterHtml;
// here I sometimes get full html but sometimes the same as in webBrowser1_DocumentCompleted method
List.Add(renderedHtml);
((Form1)Application.OpenForms[0]).Close();
}
}
}
}
I would expect that in ‘webBrowser1_DocumentCompleted’ method I could get final html. It usually works, but with this site it doesn’t. So I’ve tried get html in my own code which should be executed in web site -> method ‘CallServerSideCode’. What is strange that sometimes I get final html (basically the same as if I do it manually via Browser) but sometimes not. I think the problem is caused because my script start before whole web site is rendered instead after. But I am not really sure since this kind of things are far from my comfort zone and I don’t really understand what I am doing. I’m just trying to apply something what I found on the internet.
So, does anyone knows what is wrong with the code? Or even more importantly how to easily get final html from the site?
Any help appreciated.
You should use WebClient class to download HTML page. No display control necessary.
You want method DownloadString
May be it will be helpful if you add calling of your external function to the end of the body and wrap it by Jquery "ondomready" function. I mean something like this:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.ReadyState == WebBrowserReadyState.Complete)
{
// Final html for 99% of web pages, but unfortunately not for all
string tst = webBrowser1.Document.GetElementsByTagName("HTML")[0].OuterHtml;
webBrowser1.DocumentCompleted -= new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
HtmlElement body = webBrowser1.Document.GetElementsByTagName("body")[0];
HtmlElement scriptEl = webBrowser1.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
element.text = "$(function() { window.external.CallServerSideCode(); });";
body.AppendChild(scriptEl);
}
}
[ComVisible(true)]
public class MyScript
{
public void CallServerSideCode()
{
HtmlDocument doc = ((Form1)Application.OpenForms[0]).webBrowser1.Document;
string renderedHtml = doc.GetElementsByTagName("HTML")[0].OuterHtml;
// here I sometimes get full html but sometimes the same as in webBrowser1_DocumentCompleted method
List.Add(renderedHtml);
((Form1)Application.OpenForms[0]).Close();
}
}
im using WatiN for app im working on. in the app i got a list of sites: List<string> sites;
and i got a timer that im runing every few second to load and send data or get data from the current site.
when i try runing this code nothing happend, not even Exception. i have no idea why.
private void watiNMethod()
{
Settings.AutoStartDialogWatcher = false;
Settings.AutoStartDialogWatcher = false;
ie = new IE(webBrowser1.ActiveXInstance);
ie.GoTo(sites[runing]);
ie.WaitForComplete();
MessageBox.Show("done loading");
}
int runing;
Thread watInThread;
private void button1_Click(object sender, EventArgs e)
{
timer = new System.Windows.Forms.Timer();
timer.Start();
watInThread = new Thread(watiNMethod);
watInThread.SetApartmentState(ApartmentState.STA);
runing = 0;
}
private void timer_tick(object sender, EventArgs e)
{
if (runing <= sites.Count)
{
watInThread.Start();
}
else
{
timer.Stop();
}
runing++;
}
i want to be able to load to the web browser control, wait for him to complete with WatiN methods, and send data to the site or just get data from him.
im not sure how do this, becuse i have to use Thread to run WatiN inside the WebBrowswer Control.
(sorry for my english)
I don't think you're setting timer.Tick?!?
timer = new System.Windows.Forms.Timer();
timer.Tick += new EventHandler(this.timer_tick);
timer.Start();