I have been trying to modify an app developed by other in past ...
this app does online trading ( using api developed for C#)..so basically i have the app structure where i set few configuration paramter which user can check or uncheck and there is start and stop button
on clicking start button..i am creating a thread by passing function which will do all aping and other stuff and assigning it to main form class
betbot _mybot = this; # mybot is form class
this.main_thread = new Thread(new ThreadStart(_mybot.aping_function);
this.main_thread.Start();
and on clicking stop button,,,app is simply suspending the thread
this.main_thread.Suspend()
now the app stops and only way to resume the app function (aping) is to press start button and relaunch thread..
As a new feature , i want this thread to stop and restart automatically ..every time it hits certain stop loss and start over...but i couldn't do it
what i have tired is ManualResetEvent as following
private static ManualResetEvent mrse = new ManualResetEvent(true);
when certain event matches in aping_function method i do mrse.reset() and mrse.set()..but that seems to have not effect( not restarting completely)
if (stop_loss_condition_met)
{
this.Print1("Bot Is stopped Automatically");
mrse.Reset();
this.Print1("Bot Is re-started Automatically");
mrse.Set();
}
how can i achieve this
You should add a call of the WaitOne method at the place where your worker thread should stop.
mrse.WaitOne()
at the next time when external code reset it by call
mrse.Reset()
the execution will be stopped and thread will go to sleep at point
mrse.WaitOne()
until external code call Set method of the ManualResetEvent
mrse.Set()
Related
I am dabbling with Windows services.
From what I've read and the tutorials I've covered (one example) I see that all the work must be done in the OnStart method of the service.
As far as I understand it (from the only tutorials I was able to find, which were completely basic) after the OnStart method returns the service can't do anything if you haven't, somehow, configured it in the method.
I saw the use of timers in said method to trigger events every X seconds but what I am looking for is to detect window focus changes (when a program tries to bring its window to the front). The solution in this answer works perfectly when I try it in a console application but I want to use it in my service.
However, simply registering the eventhandler in the OnStart method does not work - it doesn't get triggered and has no effect. I tried putting a timer just to keep the OnStart method going but that didn't help, either - the timer was running and it was doing work each tick but the eventhandler never fired (I put a File.AppendText for each timer tick and each time the handler fires but in the text file I used as a control only the timer ticks were appended).
Lastly, I tried running a Task (by using Task.Run to create a new thread) which ran an endless loop in a separate method from OnStart but that just made the service start hang as it went on and on.
Code:
protected override void OnStart(string[] args)
{
File.WriteAllText("file.txt", "START");
eventLog.WriteEntry("Entered OnStart method.");
// Update the service state to "Start Pending".
ServiceStatus serviceStatus = new ServiceStatus
{
dwCurrentState = ServiceState.SERVICE_START_PENDING,
dwWaitHint = 100000
};
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Start Pending.", EventLogEntryType.Information);
// Update the service state to "Running".
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
eventLog.WriteEntry("Running.", EventLogEntryType.Information);
Task.Run(KeepBusy());
}
private static Action KeepBusy()
{
Automation.AddAutomationFocusChangedEventHandler(OnFocusChangedHandler);
while (true)
{
Thread.Sleep(1000);
}
}
In short - if I correctly understand services can only perform work in the OnStart method I am disgusted at how stupid this seems and can't figure out how to make a "listener" service
I'm developing MVC3 based web application, which at one point needs to cache large amount of data from some external database. Process takes about 10-30 min (depending on a traffic) so I put it in BackgroundWorker. When you click particular button on the webpage, using ajax it just access other method in controller, depending on the returned value proper information is displayed on user interface.
Controller:
if (IsDbLocked())
{
return this.Json(new
{
success = false,
message = "There is already an update requested by other user on the way."
});
}
this.model.DataUpdateBegin();
return this.Json(new { success = true });
Model:
public void DataUpdateBegin()
{
var backgroundWorker = new BackgroundWorker
{
WorkerSupportsCancellation = false,
WorkerReportsProgress = true
};
backgroundWorker.DoWork += this.DataUpdateWorkerDoWork;
backgroundWorker.ProgressChanged += this.DataUpdaterWorkerProgressChanged;
backgroundWorker.RunWorkerCompleted += this.DataUpdaterWorkerRunWorkerCompleted;
if (this.DataUpdateLockDb(true))
{
backgroundWorker.RunWorkerAsync();
}
}
Now when I do update, UI still freezes. While debuging controller I can see, that it starts BackgroundWorker and instantly continues to return statement (with success = true), but then it just finishes, and nothing else happens (returned message never reaches webpage).
I can see page from other browser/user and everything works ok, but this particular thread is locked for several minutes (not entire 10-30 min, as it's get unlocked after about 5 min - timeout?)
My question is, what I did wrong and how to fix it. I expect backgroundWorker to just run in the background, and free user to move around page wherever he wish. Also making an entry in database and making some external application just fetch it and do all the work (in real background) is not an option for me.
Do not use Background worker like this. Yes, the work will be done within another thread, but still in scope of that web request. Web requests are not ment to be alive for 30 minutes, there are plenty of things that can go wrong (timeouts, app pool restart, other IIS behaviour..)
If you have this type of long-running task, you should do it in some worker - windows service, maybe console application, etc. and from web you just start it (console) or set it to be done (message queue, azure queue)
Also, i hope you are not locking database (you method IsDbLocked()) for 30 minutes? Just do your import in transaction and use proper isolation level (read commited) so DB work normally all the time and the changes are there instantly when import finishes.
I'm developing MVC3 based web application
... so I put it in BackgroundWorker
BackgroundWorker is designed to work with Windows (forms) application; to achieve similar in web application, use Task.Factory.StartNew or Thread (more primitive)
I am using a Webbrowser in ASP.NET to login to a betting site and place a bet.
Once team is found and its click method raised, a side frame/window is loaded by javascript with a textbox to enter the bet ammount.
I've tried :
var stakeTextboxElement = doc.GetElementById("stake");
stakeTextboxElement.Focus();
stakeTextboxElement.InnerText = "3";
webbrowser.navigate("javascript: placeBet();"); //they use javascript
This gives me an error that my bid is not high enough (when it is). From what i can tell, its navigating too fast and not reading the InnerText as "3";
I've done the exact same scenario in Windows Forms and instead of setting InnerText, i do
SendKeys.Send("3");
webbrowser.navigate("javascript: placeBet();");
Same Error. But this works if i add 'Application.DoEvents();' just before the navigate. Doing the same does not work for the InnerText example.
From what i can tell, i have to tell webbrowser to continue running for a second or two so it reads the textbox with text inside.
Try this:
stakeTextboxElement.InnerText = "3";
DateTime dueTime = DateTime.Now.Add(TimeSpan.FromSeconds(2));
while (DateTime.Now < dueTime)
{
Application.DoEvents();
}
webbrowser.navigate("javascript: placeBet();");
Moreover you should not use InnerText which is not used by scripts to get the value of an input but rather update the Value property of the element.
stakeTextboxElement.Value = "3";
Your issue is using a control designed for UI apps on a web server. I think you are going to need to use message loops to be able to let the browser "do stuff" and then come back to you before you return your ASP.NET request to your desktop browser.
Essentially the technique is to create a new control class based on System.Windows.Forms.ApplicationContext and then set the ApartmentState to STA on creation of that control. In itself it then contains the logic to create the WebBrowser control. You then have:
the main thread which executes the ASP stuff (Page_Load etc.)
This then uses something like AutoResetEvent for signalling between threads
it passes that AutoResetEvent to the derived control that you create
it waits on that to prevent it returning your request before everything else is done
A second thread, in which the WebBrowser lives
And a third thread for the message loop, executing the WebBrowser event handles like the Navigating event handler and our callback functions. This is where you Set the AutoResetEvent to let the main thread return a response to the original caller.
The message loop can then be created by using System.Windows.Forms.Application.Run(ApplicationContext ctx), which avoids the need for a Windows Form itself in order to kick of the webbrowser.
This is really complex, but someone already did it: CodePlex: Using the WebBrowser Control in ASP.NET
Thread.Sleep
We now know this doesn't work for you
Try using Thread.Sleep:
stakeTextboxElement.InnerText = "3";
System.Threading.Thread.Sleep(3000);
webbrowser.Navigate("javascript: placeBet();"); //they use javascript
Timer with/without a reset event
This will probably have the same issues as Thread.Sleep
If that doesn't work, then schedule your Navigate call using a Timer for a few seconds later.
function void DoNavigate(Object stateInfo) {
AutoResetEvent arev = (AutoResetEvent)stateInfo; // *
webbrowser.Navigate("javascript: placeBet();"); //they use javascript
arev.Set(); // *
}
...
stakeTextboxElement.InnerText = "3";
// depending on your scenario you may need to wait for the navigate to happen, so use
// a reset event for this
AutoResetEvent arev = new AutoResetEvent(false); // *
TimerCallback tcb = DoNavigate;
Timer stateTimer = new Timer(tcb, arev, 3000, Timeout.Infinite);
arev.WaitOne(); // *
Application.DoEvents
This isn't really available in ASP.NET, but if you are using windows forms (I'm not clear from your question if you are using Win Forms or ASP.NET) and the application is freezing the UI then you may need to let it do events using Application.DoEvents.
I have a c# form, and the initialization time takes a while (its getting information from a server, and populating a TreeView). Right now, the code looks similar to this:
public class myForm : Form
{
InitializeComponent();
List<Location> locations = getServerLocations(); // Server call
foreach( Location loc in locations )
{
List<POI> POIs = loc.getLocationPOIs(); // Server call
foreach( POI poi in POIs )
{
List<POIDetails> = poi.getPOIDetails(); // Server call
....
}
}
}
you get the point I think ... So there is a large tree, and I know I can not make the calls all the way down until the user expands the tree. But the intent is I just want the Form to display, with a 'loading...' or something on a tool strip while all the processing and server gets are happening.
Right now, it seems as if I haven't loaded the application yet because nothing will show to the user until all the calls are complete.
You shouldn't do any long running processing on the UI thread - instead move this to another thread i.e using a BackgroundWorker. You can initially show the "Loading" screen and, once the background worker completes, update your UI with your tree structure.
You should work with multi threading process, so that you can separate the process that takes time from the rest of the process. Here is a blog that may help you. .NET 4.0 and System.Threading.Tasks
Running your initialization on a separate thread is the preferred way. But if you're constrained to run it on the UI thread then try calling Application.DoEvents() right after your call to .Show() or .ShowDialog() of your form.
If the form shows up, it will still be unresponsive to user actions until the initialization is completed. So running the initialization on a separate thread is the better solution.
We have a little C# startup appplication that users launch to run the latest version of our main C# WinForms application from a network share. It's kind of a simplified ClickOnce arrangement (our IT folks won't allow us to use ClickOnce).
The startup application exits after calling Process.Start("MainApplication.exe"), but the main application can take several seconds to display, leaving the user with a blank screen.
Is there a way that the starup application can poll the OS to find out if the main aplication is running before it exits? Or some other way to handle this?
You can use Process.WaitForInputIdle() to wait until your application enteres the Idle state.
Process appProcess = Process.Start("MainApplication.exe");
appProcess.WaitForInputIdle();
From MSDN:
...you have just started a process and
want to use its main window handle,
consider using the WaitForInputIdle
method to allow the process to finish
starting, ensuring that the main
window handle has been created
Remarks Section from Process.MainWindowHandle property.
You can call Process.GetProcessByName to see if the new process has been created. The other option would be to have your main application kill the startup application once it has finished loading.
Use Davids' suggestion or alternatively you can put a splash screen in your main application. It will be just a simple Form with an image running on a separate worker thread. Put this as the first item invoked on start up. Your app can continue initializing on the main thread & after some seconds or just before your Main app finishes initialization kill the worker thread.
One way to solve this easily is to use a global event to signal the startup application that the main app has reached a predetermined state. To do this create a named event handle in the startup application and wait for it to be signaled:
static void Main(string[] args)
{
const string globalName = "MyProgramName";//something unique
bool isNew = false;
ManualResetEvent mreExited = new ManualResetEvent(false);
EventWaitHandle mreStarted = new EventWaitHandle(false, EventResetMode.ManualReset, globalName, out isNew);
try
{
if (!isNew)//already running, just exit?
return;
//start and monitor for exit
Process pstarted = Process.Start("...");
pstarted.Exited += delegate(object o, EventArgs e) { mreExited.Set(); };
pstarted.EnableRaisingEvents = true;
int index = WaitHandle.WaitAny(new WaitHandle[] { mreExited, mreStarted });
if (index == 0)//mreExited signaled
throw new ApplicationException("Failed to start application.");
}
finally
{
mreExited.Close();
mreStarted.Close();
}
}
Then in the main program you signal the event once your ready for the startup application to quit:
static void Main(string[] args)
{
const string globalName = "MyProgramName";//same unique name
bool isNew = false;
EventWaitHandle mreStarted = new EventWaitHandle(false, EventResetMode.ManualReset, globalName, out isNew);
try
{
if (!isNew)
mreStarted.Set();
Application.Run(new Form());
}
finally
{
mreStarted.Close();
}
}
I think David's second option is the way to go here. The process may be running with no visible UI yet. So, once the main form is displayed in the second app, kill the first process. You could even, conceivably, pass the process id of the original process in via StartInfo when you start the new process.
There are many trade-offs involved in this, but you may be able to make start-up time fast enough to make this issue moot by using NGEN.
My suggestion is to put Splash Screen in your application it gives you a good feel rather than if you dont want to use Splash screen then kill the process when loading is finished. Or you can use Process.GetProcessByName()
For Splash Screen just make a Window Screen and in startup class just inherit the class from Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase that gives you a method OnCreateSplashScreen() Override this method like this :-
protected override void OnCreateSplashScreen()
{
base.OnCreateSplashScreen();
//yourSplashScreen is the screen you made as a window form either it would be a image or form
SplashScreen = yourSplashScreen();
}
Thanks ...Saurabh Singh Happy To Code