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.
Related
Let's suppose we have this simple classical timer in default Blazor Server.
<p>Current count: #currentCount</p>
<button class="btn btn-primary" #onclick="IncrementCount">Click me</button>
#code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
Console.WriteLine($"Count incremented: {currentCount}");
}
private Timer timer;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
timer = new Timer();
timer.Interval = 1000;
timer.Elapsed += OnTimerInterval;
timer.AutoReset = true;
// Start the timer
timer.Enabled = true;
}
base.OnAfterRender(firstRender);
}
private void OnTimerInterval(object sender, ElapsedEventArgs e)
{
IncrementCount();
InvokeAsync(() => StateHasChanged());
}
public void Dispose()
{
// During prerender, this component is rendered without calling OnAfterRender and then immediately disposed
// this mean timer will be null so we have to check for null or use the Null-conditional operator ?
timer?.Dispose();
}
}
Right now when I open this page in the browser time starts from zero for every new window(as expected). However, I want to open multiple pages in the browser and every page should see the same time (if the time shows 10 in my first window and I open a new window I want the time in both to be the same). How can I achieve that?
In general, I want to create a simple SPA that shows the real-time stock price values to the users.
Any suggestions would be appreciated.
SignalR would probably be the preferred Microsoft solution for this problem, since it provides real-time web functionality to apps.
At a high level, you would need to:
Create a Hub on the server that would be responsible for handling the connection with clients and broadcasting messages (in your case stock information).
Assuming you already have some sort of service for polling/receiving stock updates, that service could use the IHubContext to publish updates to the clients through the Hub.
The client would need a HubConnection to receive messages from the server.
Here's a full example of a Chat app using a similar approach: https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-tutorial-build-blazor-server-chat-app
Since I couldn't find a good example of an application using these components similar to your use case: I put together a simple repo that can be found here: https://github.com/t-j-c/Stack.Blazor.SignalR
Just make currentCount static.
private static int currentCount = 0;
It should work.
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.
public partial class _Default : System.Web.UI.Page
{
private static Stopwatch timer = new Stopwatch();
Thread timeThread = new Thread(timeKeeper);
private static int min = 0, sec = 0;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void startstop_Click(object sender, EventArgs e)
{
timeThread.Start();
if(timer.IsRunning()) {timer.Stop}
else timer.Start();
}
private static void timeKeeper()
{
while (timer.IsRunning)
{
mydelegate();
}
}
private static void mydelegate()
{
_Default temp = new _Default();
temp.Update();
}
private void Update()
{
min = timer.Elapsed.Minutes;
sec = timer.Elapsed.Seconds;
time.Text = min + ":" + sec;
}
}
what i want to do is have a button that controls the a stopwatch, when you click it it starts, click it again it stops. I figured the best way to do it is with a thread if i want the time.text display to continue update and to be able to click the button still. when i run the above program it gets to time.text = min + ":" + sec; and throws a nullreferenceexception. Any help on how to fix this would be greatly appreciated. I am semi new to programming in C#/asp.net.
Is there a better way of working with delegates then this. I have spent hours looking up how to use them with not many usual/easy to understand tutorials or blogs
I'm not sure where to begin.
Remember you are programming a webpage, and every call to a server result in a new webpage life cycle on the server. So using threads in a webpage will not result in the correct behaviour.
To get the kind of behaviour you want, you'll have to do the timer and click handling on the client instead of the server. You can use jQuery to facilitate in this. One other option is to use ajax if you have to keep the server up-to-date.
It seems that the problem is here:
_Default temp = new _Default();
The new class isn't passing through the ASP.Net pipeline, so when you try to update a control in the markup (time), it has not actually loaded.
I think your approach here is a bit flawed. If you want to do it on the server side, you'll need to use repeated Ajax requests (or a web socket) to keep the browser in sync with the timer object on the server. Not to mention, what happens when you have multiple users and the threads start colliding? It seems like it would be far better to use Javascript.
In my application I have a button to save some information. However, I would like to have a delay in the code before the last line is executed, so that the user could read the message that shows up before he gets redirected to the new page.
I know that doing this isn't at all an optimal way, but by some reasons (time, for example) I want to do it anyway.
So is it possible and if so, how could I do it?
Thanks in advance!
protected void SaveButton_Click(object sender, EventArgs e) {
// Lots of code not relevant for the problem here
Service service = new Service();
service.SaveMovie(movie);
successMessage.Visible = true;
happyMessage.Text = "The movie was successfully added, now add some genres!";
// Here I want a delay of 2 seconds before the next line is executed...
Response.Redirect(String.Format("~/Edit.aspx?id={0}", movie.MovieID), false);
}
You need to do this on the client side. One alternative is this:
Define a Javascript function in the page called redirect as so:
function redirect(url)
{
setTimeout(function(){window.location.href=url;} ,2000);
}
protected void SaveButton_Click(object sender, EventArgs e)
{
// Lots of code not relevant for the problem here
Service service = new Service();
service.SaveMovie(movie);
successMessage.Visible = true;
happyMessage.Text = "The movie was successfully added, now add some genres!";
// Here I want a delay of 2 seconds before the next line is executed...
ClientScript.RegisterStartupScript(this.GetType(),"somekey","redirect('"+String.Format("~/Edit.aspx?id={0}", movie.MovieID)+"');");
}
This will be easy if you are using Javascript. Use javascript will boost performance
Button_Click
{
string js ="<script type='text/javascript'>setTimeout(function()window.location.href="+String.Format("~/Edit.aspx?id={0}", movie.MovieID)+";} ,2000);</script>"
ScriptManager.RegisterStartupScript(Me.Page, GetType(Page), "js", js, False)
}
possible duplicate of
asp.net delay before response redirect
I'm a learn-by-example C# coder who isn't very advanced, which is why this problem is completely stumping me regardless of the amount of information on the internet.
I'm essentially creating a program that is, on a timer, repeatedly polling a website to get some information. During this process, a WebBrowser control is created to navigate to the information (needed for authentication). The program runs this series of events at startup, then using a System.Timers.Timer set to every 10 minutes (less for debugging of course) to do that same series of events yet when my Timer.Elapsed event triggers that process, I get a:
ThreadStateException with the description as ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment.
Here is a slimmed down version of my program.
private void Form1_Load(object sender, EventArgs e)
{
GetDataFromWebBrowser();
Set_Auto_Refresh_Timer();
}
private void Set_Auto_Refresh_Timer()
{
System.Timers.Timer TimerRefresh = new System.Timers.Timer(10000);
TimerRefresh.Elapsed += new System.Timers.ElapsedEventHandler(TimerRefresh_Elapsed);
TimerRefresh.AutoReset = true;
TimerRefresh.Start();
}
private void TimerRefresh_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GetDataFromWebBrowser();
}
private void GetDataFromWebBrowser()
{
WebBrowser wb = new WebBrowser(); <--This is where the error is thrown.
...get web data...
}
I think I got enough code in there to paint the picture. As you can see, when it gets to creating another WebBrowser, it throws the error.
I'm really stumped and I'm just starting to scrape the surface on Threading which is probably why I'm so stumped.
//Solution for me/
I ended up moving the WebBrowser creation out of the method as well as making it static to just reuse the WebBrowser control. I also swapped my System.Timers.Timer to System.Threading.Timer. Seemed to fix the problem.
The MSDN documentation for WebBrowser states that:
The WebBrowser class can only be used in threads set to single thread apartment (STA) mode. To use this class, ensure that your Main method is marked with the [STAThread] attribute.
Also, change your System.Timers.Timer to a System.Windows.Forms.Timer if you want to interact with UI controls in regular intervals. Alternatively, set the SynchronizingObject property of your System.Timers.Timer to a parent control to force your timer to invoke calls on the right thread. All WinForms controls can only be accessed from the same, one and only UI thread.
There are three types of timers in .NET's BCL, each of them acting very differently. Check this MSDN article for a comparison: Comparing the Timer Classes in the .NET Framework Class Library (web archive) or this brief comparison table.
I would recommend using WebClient class instead of WebBrowser. Also it seems to be better to store already created instance as a private property instead of creating new instance each time you need to poll a web site.
As following:
private WebClient webClient;
private void Form1_Load(object sender, EventArgs e)
{
GetDataFromWebBrowser();
Set_Auto_Refresh_Timer();
this.webClient = new WebClient();
}
private void Set_Auto_Refresh_Timer()
{
System.Timers.Timer.TimerRefresh = new System.Timers.Timer(10000);
TimerRefresh.Elapsed += new System.Timers.ElapsedEventHandler(TimerRefresh_Elapsed);
TimerRefresh.AutoReset = true;
TimerRefresh.Start();
}
private void Set_Auto_Refresh_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GetDataFromWebBrowser();
}
private void GetDataFromWebBrowser()
{
...perform required work with webClient...
...get web data...
}
As Groo said, you should use System.Windows.Forms.Timer, or if you really want to do you operation in another thread, you should use the Invoke method to do any UI related stuff:
private void GetWebData()
{
...get web data...
}
private void ShowWebData()
{
WebBrowser wb = new WebBrowser();
// other UI stuff
}
private void TimerRefresh_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
GetDataFromWebBrowser();
}
private void GetDataFromWebBrowser()
{
GetWebData();
if (this.InvokeRequired)
this.Invoke(new Action(ShowWebData));
else
ShowWebData();
}