Get Progress status of a long executed SP in Asp.net? - c#

I have SP in SqlServer (2005+) which uses cursor and do some stuff (on 10,000 rows)
I need something like a progress bar ( to see in my c# web site.).
I can take the 10,000 divided by 100 in such that each 1000 records it will do ( using sql print command) : process of another 1000 is done !!!
But I want to catch that print ( each new print) in my asp.net web site.
how can I catch the print commands / or is there any better way of doing this ?

The process we used to implement something similiar is a little more complicated, but it does work.
We created a webservice that had a number of methods, for example;
[SoapDocumentMethod(OneWay = true), WebMethod]
public void StartUpdate(string reference)
[WebMethod]
public ProcessStatus GetProcessStatus(string reference)
A call to the asynch webmethod would start the process running and passed in a reference number to identify itself. This in turn called a stored procedure which used an update on iterations of the cursor to update another table with 'reference', 'count' and 'status'
The GetProcessStatus would then pass this reference in and pass back the current count and status. If the status was completed, we could move on, alternatively, you could use the 'count' at this point to update the status. An example of this;
protected void Page_Load(object sender, EventArgs e)
{
this.JavaScript.Text = string.Format("<script>setTimeout(\"{0}\", {1});</script>",
this.Page.GetPostBackClientEvent(this.btnRefresh, ""), 3000);
ProcessStatus status= Class.GetProcessStatus(reference);
lblCount.Text = status.Count.ToString();
if (import.Status == (int)ProcessStatus.Status.Complete)
{
Globals.GoUrl("/Import/File/Map.aspx");
}
}
Hope that helps.

Related

MessageBox and while loop C#

I'm modifying existing C# code in order to pilote a piston. Every 30ms, I have a direct feedback of the position of this piston, through an event. The value is stored in a global variable I use to get the current position of the piston.
What I'm trying to achieve: for a given distance input (A->C), I want the piston to travel at full speed for 95% of the distance (A->B), and then slower for the remaining 5% (B->C).
I have access to a command that defines the speed and the destination of the piston : pos(velocity, destination).
However, if I write that code:
pos(fullSpeed,B);
pos(reducedSpeed, C);
the piston directly goes from fullSpeed to reducedSpeed
I tried to use a while loop to compare the current position of the piston with the goal destination, however, upon entering the while loop, the variable storing the piston position does not update anymore.
However, I noticed that by throwing a MessageBox in between, the position value keeps on getting updated, and I can simply click "ok" to launch the second command.
pos(fullSpeed,B);
MessageBox.show("Wait");
pos(reducedSpeed, C);
I would like to know why the "while" loop stops the update of the position variable but the MessageBox does not. I mean, as long as I don't click the "ok" button, the box is here preventing me from doing anything, which for me ressembles a while loop behaviour. Is there another way for me to do this instead of the MessageBox ?
I have little to no knowledge when it comes to C# and no support. I have tried to look in the documentation, but I did not find an answer (I have probably missed it). Any lead is more than welcome.
EDIT: I have no documentation for that code, and it is barely commented. Here is what I gathered (really hope it helps):
To move the piston, taht function is called:
MyEdc.Move.Pos(control, speed, destination, ref MyTan);
control simply define what we pilote (a distance or a load, it is an enum), and I have no idea what MyTan does. Only thing I know is that the MyEdc.Move.Pos returns an error code.
If I look at the definition of "pos", I am redirected to class
public DoPEmove Move;
containing among other things:
public DoPE.ERR Pos(DoPE.CTRL MoveCtrl, double Speed, double Destination, ref short Tan);
DoPE.ERR is also an type enum. However, I cannot reach the definition of a function named "Pos". Coud it be within the .dll included ?
The following is the code that allows me to access the position of the piston (without the global variables):
private int OnData(ref DoPE.OnData Data, object Parameter)
{
if (Data.DoPError == DoPE.ERR.NOERROR)
{
DoPE.Data Sample = Data.Data;
Int32 Time = Environment.TickCount;
if ((Time - LastTime) >= 300 /*ms*/)
{
LastTime = Time;
string text;
text = String.Format("{0}", Sample.Time.ToString("0.000"));
guiTime.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_S].ToString("0.000"));
guiPosition.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_F].ToString("0.000"));
guiLoad.Text = text;
text = String.Format("{0}", Sample.Sensor[(int)DoPE.SENSOR.SENSOR_E].ToString("0.000"));
guiExtension.Text = text;
}
}
return 0;
}
Which is called using
MyEdc.Eh.OnDataHdlr += new DoPE.OnDataHdlr(OnData);
I realise how little I know on how the soft operates, and how frustrating this is for you. If you think this is a lost cause, no problem, I'll try Timothy Jannace solution, and if it does not help me, I'll stick with the MessageBox solution. I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
I tried to use a while loop to compare the current position of the
piston with the goal destination, however, upon entering the while
loop, the variable storing the piston position does not update
anymore.
While you are in the while loop, your app can no longer receive and process the feedback event.
One possible solution would be to use async/await like this:
private const int fullSpeed = 1;
private const int reducedSpeed = 2;
private int currentPistonPositon = 0; // global var updated by event as you described
private async void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
pos(fullSpeed, B);
await Task.Run(() =>
{ // pick one below?
// assumes that "B" and "currentPistonPosition" can actually be EXACTLY the same value
while (currentPistonPositon != B)
{
System.Threading.Thread.Sleep(25);
}
// if this isn't the case, then perhaps when it reaches a certain threshold distance?
while (Math.Abs(currentPistonPositon - B) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
pos(reducedSpeed, C);
}
Note the button1_Click method signature has been marked with async. The code will wait for the while loop inside the task to complete while still processing event messages because of the await. Only then will it move on to the second pos() call.
Thank you for your answer ! It works like a charm ! (good catch on the
EXACT value). I learnt a lot, and I am sure the async/await combo is
going to be very usefull in the future ! – MaximeS
If that worked well, then you might want to consider refactoring the code and making your own "goto position" method like this:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
GotoPosition(fullSpeed, B);
GotoPosition(reducedSpeed, C);
}
private async void GotoPosition(int speed, int position)
{
pos(speed, position);
await Task.Run(() =>
{
while (Math.Abs(currentPistonPositon - position) > 0.10)
{
System.Threading.Thread.Sleep(25);
}
});
}
Readability would be greatly improved.
You could even get fancier and introduce a timeout concept into the while loop. Now your code could do something like below:
private void button1_Click(object sender, EventArgs e)
{
int B = 50;
int C = 75;
if (GotoPosition(fullSpeed, B, TimeSpan.FromMilliseconds(750)).Result)
{
if (GotoPosition(reducedSpeed, C, TimeSpan.FromMilliseconds(1500)).Result)
{
// ... we successfully went to B at fullSpeed, then to C at reducedSpeed ...
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
else
{
MessageBox.Show("Piston Timed Out");
}
}
private async Task<bool> GotoPosition(int speed, int position, TimeSpan timeOut)
{
pos(speed, position); // call the async API
// wait for the position to be reached, or the timeout to occur
bool success = true; // assume we have succeeded until proven otherwise
DateTime dt = DateTime.Now.Add(timeOut); // set our timeout DateTime in the future
await Task.Run(() =>
{
System.Threading.Thread.Sleep(50); // give the piston a chance to update maybe once before checking?
while (Math.Abs(currentPistonPositon - position) > 0.10) // see if the piston has reached our target position
{
if (DateTime.Now > dt) // did we move past our timeout DateTime?
{
success = false;
break;
}
System.Threading.Thread.Sleep(25); // very small sleep to reduce CPU usage
}
});
return success;
}
If you're using events you are probably having concurrency issues. Especially with events being raised every 30ms!
A very simple way to handle concurrency is to use a lock object to prevent different threads from using contested resources simultaneously:
class MyEventHandler
{
private object _lockObject;
MyEventHandler()
{
_lockObject = new object();
}
public int MyContestedResource { get; }
public void HandleEvent( object sender, MyEvent event )
{
lock ( _lockObject )
{
// do stuff with event here
MyContestedResource++;
}
}
}
Keep in mind that is very simple and by no means perfect in every scenario. If you provide more information about how the events are raised and what you're doing with them people will be able to provide more help.
EDIT:
Using that signature you posted for the Pos method I was able to find documentation on the library you are using: https://www.academia.edu/24938060/Do_PE
The reason you only see the method signature when you goto definition is because the library has been compiled into a dll. Actually, it probably wouldn't be that useful to see the code anyway because it looks like the library is a C# wrapper around native (c or c++) code.
Anyways, I hope the documentation is helpful to you. If you look at page 20 there are some pointers on doing movement. This is going to be a challenge for a new programmer but you can do it. I would suggest you avoid using the event handler to drive your logic and instead stick with using the synchronous versions of commands. Using the synchronous commands your code should operate the same way it reads.
I believe what you'll want to do is add a call to:
Application.DoEvents();
This will allow your application to process posted messages (events), which will allow that global variable to be updated.
I just wanted to know why the MessageBox allowed me to sort of achieve my objectif, but the while loop did not, and how to use it in my advantage here.
The reason that works is because you're giving the WndProc a chance to process events which have been sent to the application. It's not an intended feature of that call to MessageBox.Show();, but it is a consequence. You can do the same thing with a call to Application.DoEvents(); without the interruption of the message box.

ontextchanged async sql stored proc call

I have a winform application and on the main form I placed a textbox.
What I want is that on the OnTextChanged event I need to query sql (stored proc) table in order to bring a list of matches with the character typed. For example if I type letter A then automaticly I should go and search in the database for names starting with letter "A", if I then type letter "L" then I should go and search for names starting with "AL" and so on.
The thing is that If I the user type fast then It should cancel any async process that is in progress and keep only the task for the last letter typed.
Any clue on how to achieve these?
The thing is that If I the user type fast then It should cancel any async process
It shouldn't need to cancel anything - the trick is not to start anything until you think the user has stopped typing.
I wrote something a bit similar, whereby when the user typed I had a thread start a new method, the method waited for a (configurable) time before executing. Another keystroke would call the method again and reset the wait period - effectively if someone continued to type the task wouldn't execute; as soon as they stopped it would (after a 200 ms pause for example).
I would implement something similar if I were you, as it avoids going to SQL when you don't have to
updated - by way of a simple example, a new project with a new form and default text box should allow the following code to function for your needs (as a very simple starting point)
public partial class Form1 : Form
{
private bool _waiting;
private bool _keyPressed;
private const int TypingDelay = 220; // ms used for delay between keystrokes to initiate search
public Form1()
{
InitializeComponent();
}
private void WaitWhileUserTyping()
{
var keepWaiting = true;
while (keepWaiting)
{
_keyPressed = false;
Thread.Sleep(TypingDelay);
keepWaiting = _keyPressed;
}
Invoke((MethodInvoker)(ExecuteSearch));
_waiting = false;
}
private void ExecuteSearch()
{
Thread.Sleep(200); // do lookup
// show search results...
MessageBox.Show("Search complete");
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (_waiting)
{
_keyPressed = true;
return;
}
_waiting = true;
// kick off a thread to do the search if nothing happens after x ms
ThreadPool.QueueUserWorkItem(_ => WaitWhileUserTyping());
}
}

Calling a javascript function asynchronosly from server side in c#

this is my code :
protected void BtnImport_Click(object sender, EventArgs e)
{
List<DataTable> tb = Helper.SplitTableToManyTables(FileTb, 50); // a list containing multiple DataTable each have 50 rows
int importedRowsCount = 0;
for (int KLoop = 0; KLoop < tb.Count; KLoop++)
{
...
if (QueriesDataHelper.ImportContacts(resTb, int.Parse(TxtHiddenGroupId.Value), Session))
{
importedRowsCount += resTb.Rows.Count;
var script = "DisplayProgressMsg(" + importedRowsCount + ")";
ScriptManager.RegisterStartupScript(this, GetType(), "MyScript", script, true);
if (KLoop == tb.Count - 1)
MessageBox.Show(importedRowsCount.ToString()+" Contacts imported successfully");
}
}
}
QueriesDataHelper.ImportContacts is a function that take a dataTable containing 50 rows and send it to a stored procedure
my problem is RegisterStartupScript is beeing executed after all the dataTables are beiing inserted i want to display a ms after the first DataTable finish tha
Ok,
Http is request/response protocol. But you want send do multiple responses for single request.
I see two ways for you. In both, you will have to run your long running process in separate thread. Then
1) use ajax, to ask server about progress every N seconds, and display result. Client's will track progress with some delay
2) web sockets(SignalR is great for such purposes). In this way you will be able to display progress in real time, but i think it's harder to implement

Chip8 Emulator - User Input

I have been writing a chip8 Emulator -- http://en.wikipedia.org/wiki/CHIP-8
I have tested all of the opcodes as well as the graphics calculations and I am now struggling with the user input. I have the following method monitoring user input and altering the registers as needed (When using the chip8 the user input alters the corresponding memory register - E.G. hitting '0' sets the V0 register to 0.
My problem is that I have the following code fetching and calculating each opcode and its operation contained in a while loop. And while this is running my application cannot detect user input. So the ROMS start and just stay locked in place waiting on a register change or user input. It keeps getting stuck in an infinite loop, I tried to implement a global Boolean RUN, and it is not detected after the while loop is initiated. I'm assuming it is out of the scope of the loop, but from what I have read, the keyboard event triggers an interrupt that should be visible from almost anywhere, any Thoughts?
This is what calculates and parses the opcode
private void button1_Click(object sender, EventArgs e)
{
// This will become the run function
do{
for (int i = 0; i < 2; i++)
{
opc[i] = mem[mc]; // fetching the instruction from the memory array
mc++;
}
cibox.Clear(); // Just clearing Debugging text boxes in the UI
pcbox.Clear();
pc++;
pcbox.Text += pc;
cibox.Text += opc[0].ToString("X2") + "-" + opc[1].ToString("X2");
calculations(opc); // Parses the Opcode and does the corresponding operation
}while(run);
}
And this method is controlling the user input...
protected override void OnKeyDown(KeyEventArgs keyEvent) // Listens for Keyboard events! Read More: http://www.geekpedia.com/tutorial53_Getting-input-from-keyboard.html
{
keyPress = true;
//Gets the key code found at keyEvent...
MessageBox.Show("KeyCode: " + keyEvent.KeyCode.ToString());
String register = keyEvent.KeyCode.ToString();
if (register == "Escape")
{
Application.Exit();
run = false;
}
try
{
registerVal = int.Parse(register, System.Globalization.NumberStyles.HexNumber); // Second Nibble! --> Int Format
}
catch (System.ArgumentNullException e)
{
return;
}
catch (System.ArgumentException)
{
return;
}
catch (System.FormatException)
{
return;
}
catch (System.OverflowException)
{
return;
}
if (registerVal >= 208)
{
registerVal = registerVal - 208;
}
if (registerVal <= 15)
{
mem[registerVal] = (byte)registerVal;
}
display(); // Alters UI to display state of registers, etc
}
So I have now tried the Game Loop Idea, but I cannot find a way to make a method in C# that will return a key press. Maybe I am missing something here, but I cannot seem to figure it out!
I also tried another method involving running the CPU calculations in a separate thread, and this is causing a slight delay issue.
I would really like to see an example of a method in C# that returns the value of a key being pressed that I can call within the While loop!
I suggest you set up your emulator's loop like a game loop. You have one global loop which triggers updates to each module in your emulator. In the loop, you call your input (or generic "event") processor, then your opcode/hardware emulation, then your screen update.
Here's some pseudo-code.
while (True):
processInput()
updateCPU()
outputGraphics()
I don't know how the key input works in C#, if it's an asynchronous event trigger (i.e. the "OnKeyDown" method gets called outside of your loop), you can set up "OnKeyDown" to just send the key events to an intermediate event manager, then in "processInput()" you actually resolve the events and use them to update registers on the emulated CPU etc.

C# winform backgroundworker

I am currently working on a home project for myself.
The program is written in C# using winforms.
The problem I'm currently experiencing is as followed:
I have a listview in my mainform called lvwGames
When I run the program without debugging, it runs fine.
However when I start with a debug, I get an error. This has something to do with the background worker thread.
Allow me to post some code to assist me.
private void MainViewLoad(object sender, EventArgs e)
{
RefreshGamesListView();
}
Nothing special here.
The reason I am calling RefreshGamesListView() is because I have to refresh on several occasions.
The method being called looks like this.
public void RefreshGamesListView()
{
pbRefreshGamesList.Value = 0;
bgwRefreshList.RunWorkerAsync();
}
So when the method is called, the background worker is called and runs the dowork method.
This one is quite big.
private void BgwRefreshListDoWork(object sender, DoWorkEventArgs e)
{
List<Game> games = _mainController.RetrieveAllGames();
int count = 1;
foreach (Game game in games)
{
string id = game.id.ToString();
var li = new ListViewItem(id, 0);
li.SubItems.Add(game.title);
li.SubItems.Add(game.Genre.name);
li.SubItems.Add(game.Publisher.name);
li.SubItems.Add(game.Platform.name);
li.SubItems.Add(game.CompletionType.name);
li.SubItems.Add(game.gameNotice);
lvwGames.Items.Add(li);
double dIndex = (double)(count);
double dTotal = (double)games.Count;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
count++;
bgwRefreshList.ReportProgress(iProgressPercentage);
}
}
When i run the code in debug, when the code is on lvwGames.Items.Add(li);
It gives me the following error:
Cross-thread operation not valid: Control 'lvwGames' accessed from a thread other than the thread it was created on.
I have absolutely no clue why.
I think it is code specific. But it can also mean I don't get the background worker completely, and specifically when to use it properly.
The reason I'm using it is because I'm loading a large large list from the database, I want to keep responsiveness in the UI when the list is loaded, and inform the users how far it is, using a progress bar.
If any code is missing, or you actually understand why this is happening PLEASE explain me why in this case its causing the error. You don't need to fix it for me. I just want to know WHY it's caused.
Thanks for taking the time to read this post. I hope to be able to continue using the debugger soon. :)
You need to call Conrol.Invoke when accessing visual controls from background threads.
if (_lvwGames.IsHandleCreated) {
Action addGameToList = () => {
string id = game.id.ToString();
var li = new ListViewItem(id, 0);
li.SubItems.Add(game.title);
....
_lvwGames.Items.Add(li);
};
if (_lvwGames.InvokeRequired) {
_lvwGames.Invoke(addGameToList);
} else {
addGameToList();
}
}
From Manipulating Controls from Threads
...For example, you might call a method that disables a button or
updates a display on a form in response to action taken by a thread.
The .NET Framework provides methods that are safe to call from any
thread for invoking methods that interact with controls owned by other
threads. The Control.Invoke method allows for the synchronous
execution of methods on controls...
This is because you're attempting to access a UI control (lvwGames) from a background thread. The way to make it work requires you to marshal the information back to the main UI thread and update the control from there:
private void BgwRefreshListDoWork(object sender, DoWorkEventArgs e)
{
List<Game> games = _mainController.RetrieveAllGames();
int count = 1;
foreach (Game game in games)
{
string id = game.id.ToString();
var li = new ListViewItem(id, 0);
li.SubItems.Add(game.title);
li.SubItems.Add(game.Genre.name);
li.SubItems.Add(game.Publisher.name);
li.SubItems.Add(game.Platform.name);
li.SubItems.Add(game.CompletionType.name);
li.SubItems.Add(game.gameNotice);
// This is the new line you need:
lvwGames.Invoke(new MethodInvoker(delegate { lvwGames.Items.Add(item) }));
double dIndex = (double)(count);
double dTotal = (double)games.Count;
double dProgressPercentage = (dIndex / dTotal);
int iProgressPercentage = (int)(dProgressPercentage * 100);
count++;
bgwRefreshList.ReportProgress(iProgressPercentage);
}
}
Normally you would check the InvokeRequired property first as mentioned in other answers, but there is really no need if you are always calling it from the background thread. Your DoWork method will always require an invoke call, so you might as well just go ahead and write it like that.
This happening cause, just like compiler cliams, you are going to update UI control content from another thread. You can not do that, as UI control can be updated only within main thread.
Please have look on this SO answer with example code provided:
Invoke from another thread
The background worker is not working properly if you run in debug mode in studio. If you have calls that use the windows handle to retrieve messages, then they will fail. If you for instance have a progressChanged event handler and this changes a text in a textbox that might fail.
I had this scenario: A Form that has a background worker. If I just start the worker without getting a dialog box up first then it works ok. If I show a dialog and then start the background worker then it fails. When I run the program normally it does not fail. It is somehow the debug environment that destroys the link between the events and the foreground window. I have changed my code to use invoke, and now all works both in when running in release and when I debug.
Here is a link explaining what can be done to make a program thread safe.
http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx
I did not do the same as the sample to microsoft. I made delegates, assigned to the functions I needed to run. and called invoke on them.
sample pseudo code:
class MyClassWithDelegates
{
public delegate void ProgressDelegate( int progress );
public ProgressDelegate myProgress;
public void MyProgress(int progress)
{
myTextbox.Text = ..... ; // this is code that must be run in the GUI thread.
}
public MyClassWithDelegates()
{
myProgress = new ProgressDelegate(MyProgress);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
Invoke( myProgress, e.ProgressPercentage );
}
}
All code that potentially have to be run in the GUI thread of the application must be Invoked to be safe.

Categories