Display Progress Label while fetching data - c#

Here is how I am trying to do:
void Fetch()
{
//Code To Fetch Data
}
protected void btn_Click(object sender, EventArgs e)
{
lblSatus.Text = "Fetching Data...";
Thread t = new Thread(Fetch);
t.Start();
t.Join();
lblSatus.Text = "Got Data";
}
But on click of button it directly display GotData.
Any idea what I am doing wrong here.
Thanks

After the t.Start(); you need something that does a check ...along the lines of:
while (!t.Completed) // pseudo
{
// wait
Thread.Sleep(10);
}
Otherwise, the thread spins up and begins execution while the Main thread simply falls through.

I think you're misunderstanding the relationship between threads on the server-side when processing an ASP.NET request, and the experience on the browser-side. Specifically, for a given HttpRequest (in your example, the Request is a postback, which triggers the btn_Click event), there will be one and only one Response. This is true, regardless of what thread-manipulation you're doing on the server-side.
In your example, it looks like you're expecting the server to respond to the browser, with lblSatus's value as "Fetching data...". Then a little later when the operation has completed, the server would "respond" to the browser again, with lblSatus's value as "Got Data". This will not work, due to the "handshake" nature of Http communication: one request will result in one response (and thus, only one value for lblSatus).
The thing you're trying to do (give the end user a logical "progress bar" during a long-running operation) is a common requirement. Unfortunately, I know of no easy built-in way to do this in ASP.NET. I suspect most people do it via a polling model: the browser initiates the action, the server kicks it off in some sort of asynchronous fashion that does NOT delay the response being sent back to the browser. Then the browser periodically (via javascript, most likely) reaches back to the server to get an update on the operation's progress.

Related

What is the best way to cancel a task on a web form

I have a long task that runs, and can take up to 15 minutes, I allow the user to only run one at a time. This all works well but I can't get my results and have a cancel button.
Currently I have the cancel button write a file, and if that file is present during a loop, the task completes and self deletes. However, I can't get the results of the task to do anything, so errors aren't reported or anything. What is your recommendation on doing this?
Libraries needed for below (iirc)
using System
using System.Threading
using System.Threading.Tasks
Here is a rough example of my execution code.
protected void Execute_Click(object sender, EventArgs e)
{
Task taskExecute = new Task(()=>
{
// 15 minute task
// I also look for cancelation file during loop periodically.
}
taskExecute.Start();
// If i wait for the task, it freezes the webpage so this is commented out
// taskExecute.Wait();
}
here is my cancelation code:
protected void Cancel_Click(object sender, EventArgs e)
{
//code to write file that long script looks for...
}
If you're wondering, the code is called via <asp:button onclick="Execute_Click"> calls. etc...
Also, I can click the cancel button if I refresh the page, but that defeats the purpose, as the responses in my results box won't be visible.
What you're looking for can be accomplished with Azure Durable Functions and add in SignalR/Websockets if you're looking to track state in real-time without polling.
Calls to durable functions return with an ID that you can check on intermittently using a built-in state management endpoint on your function. State objects support custom data as well. This loose coupling allows you to execute and forget calls to the API without blocking any threads. Each call returns a unique ID, so you can run multiple instances in parallel, and easily track them. Connect your web client and web service to a websockets channel (SignalR), and you can send real-time updates or events from your webservice TO your webclient, including a "process completed" event that you can use to trigger the download/render of output/logs/etc...

How to covert async call to work as sync call in C#

I'm a newbie in C#, and I'm going to develop a small program using a third party network library to send the requests.
Suppose there have some requests (just simple strings) stored in the queue qTasks, and it will handle those requests one by one with the order as submitted, the queue can be updated during execution, and it should be stopped whenever there has error returned.
I can just use a for loop to call the send request command in the array one by one, but unfortunately the sendrequest command is an async method with callback OnStageChanged, and I need to check the result before sending the next request when the status is "Done".
I'm now using the following method to handle it:
In the main UI Thread,
// Put those request text in a queue names qTasks, then call a goNextTask() to process the request one by one.
// The queue can be updated by the UI thread at anytime, goNextTask will be called periodically to handle those pending request in the queue.
private void goNextTask(bool lastSuccess = true)
{
if (lastSuccess)
{
if (qTasks.Count > 0)
{
// continue to next request
string requestText = qTasks.Dequeue();
SendRequest(requestText, OnStageChangeHandler);
} else {
// Report for all request sent successfully
}
} else {
// stop and show error
}
}
The callback method OnStageChangeHandler will be called by the library whenever the stage changes, and it will have state "Done" when completed.
private void OnStageChangeHandler(object sender, StageChangeEventArgs e)
{
if (e.newState == SessionStates.Done)
{
// check result here
bool success = <...>
// then call the goNextTask in UI thread with the result of current request.
Application.Current.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() => goNextTask(success)));
}
}
Although it works fine now, I think it's a little bit stupid as it has a somewhat recursive flow (A -> B -> A -> B ->....).
I learnt that MS has improved the web request handling, so that it can work in sync mode.
I'd like to know if I can have a wrapper to make the above async call work as a sync call, so that it can be done in a simple flow as a loop like that:
while (qTaks.Count > 0)
{
if (!sendAndWaitReturn(qTasks.Dequeue())) {
// Report error and quit
}
}
// all tasks completed
This sendAndWaitReturn method will send the request, then wait for the status "Done", and then return the result.
I found some example that may use a control flag to indicate the status of the current request, and the callback function will update this control flag, while the UI thread will loop on this flag using a while loop:
while (!requestDone);
so that it will not continue to nextRequest until requestDone. But in this case, the UI will be blocked.
Is there any better way to convert the async call to work as a sync call without blocking the UI thread?
The difficulty you're going to run into is you have conflicting desires. On one hand, you want to avoid blocking the UI thread. On the other hand, you don't want to run things asynchronously and so you're going to block the UI thread.
You're going to have to pick one, and there's absolutely no reason to keep on doing things synchronously (especially in light of blocking the UI thread). If it hurts when you do that, don't do that.
You haven't specified, but I'm guessing that you're starting this processing from a button click event. Make the method invoked by that click event async. For example:
private async void StartProcessing_Click(object sender, EventArgs e)
{
await Task.Run(() => StartProcessing());
}
There, you've started processing and the UI thread isn't tied up.
The next thing is that, you're right, having the event behave in that cyclical manner is silly. The event is to notify someone that the state has changed, its goal isn't to manage queue policy. The queue should manage queue policy (or if you'd rather not abstract that out, the method that processes requests).
So how would you do that? Well, you've said that SendRequest hands the session object back to the caller. The caller is presumably the one who is orchestrating queue policy and determining whether or not to call SendRequest again.
Have the caller check the session object for validity and decide whether to keep going based on that.
Additionally, I'm unfamiliar with that particular library, but briefly glancing at the documentation it looks like there's also a SendRequestAndWait() method with the same signature and that sounds like it might better meet your needs.

C# Calling an action asynchronously

I have a form post which should call an action asynchronously.
public async Task<ActionResult> SaveW2Document(Models.DocumentData documentData)
{
some code here
var ID = await Task.Run<int>(() => somObject.SaveDocument(uploadDocument));
//Code that uses ID
if(ID == something){
//Do something
}
}
However it gets called synchronously and my other actions do not execute until this action gets completed.Is it something else that I need to do?
I have a form post which should call an action asynchronously.
I think you're misunderstanding what "asynchronous" means in this context. Using async controller actions (or HTTP request handlers in general) means that the web server can invoke the operations asynchronously and not hold a thread in a wait state while the operation completes. This allows the web server to handle more concurrent requests more effectively.
The browser, however, is waiting for the response. The asynchronous nature of any given operation generally isn't defined by the operation itself, but by whatever invokes it. (For example, note how within this operation there is another asynchronous operation being awaited. If this code didn't await it, the behavior would be very different. But the method being invoked wouldn't change between those two scenarios.)
This makes sense, though. After all, what is the browser going to do if it doesn't wait for the response from the server? Display a blank page?
You can make asynchronous calls to a web server from client-side code by way of using AJAX. That would allow the page to invoke the server-side operation and listen for the response without blocking or changing the context of the page itself. But if the whole page context is posting to the server and waiting to load a new page, it needs to receive that new page before it can display it.
Well I might not have been able to ask the question correctly.But I found the solution to the problem that was occuring. MVC has a behaviour that blocks concurrent requests coming from the same session.I will either have to Disable Session or make it readonly for that controller. Refer this link.
So adding [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)] to my controller helped.

App for monitoring changes

I am writing a GUI app for monitoring and I'd like to get some advice on it's logic. Basically all the app needs to do is connect to a distant server every x minutes, check if something was changed, get changes if any, act upon them (update local db and so on, depending on changes).
My first idea was:
Have a checkbox (monitoring on/off). On click (if checked) starts a Timer.
Timer launches a BackgroundWorker in it's Tick method.
DoWork method does the connecting / retrieving info stuff
a) on WorkDone handler method gets the info from background worker and does local updates with it
b) on WorkDone handler method triggers one or more of custom events "SomethingChanged" depending on changes it got; EventListeners handle local updates from there.
My main problem is calling Worker from Timer since I added Worker to the Form and now they are on different threads (is that correct description?) and then passing results around is a similar problem. I was reading about delegates but still not sure what to use when and how, and if it's really necessary in the first place. Do I need both bgWorker and Timer? Do I need custom events or can I just do all work inside workDone with Switch(result)? Is this general principle good in the first place, maybe there's something better and I am reinventing the wheel? Thank you in advance!
From an architecture point of view:
Message Queues decouple bits of your application. You can in Windows Forms applications rely on the Message Queue that Windows creates and manages for you. Google for PostMessage/GetMessage etc. This is generally called "message passing".
Typical Arcitecture
One part of your app "pushes" a request into a queue
Some other part of your app "pulls" a request from a queue and writes a result to a second queue.
The first part can then "pull" requests from the second "results" queue and display to a user.
So it looks like this:
App --> REQUESTS QUEUE --> processing engine --> RESULTS QUEUE --> App
The processing engine could be in the same app, on the same thread or in a different thread/process (or even different machine).
You can use simple queues : say a Queue<string>() (as long as you use locks to access it) or increase complexity or more and more complex/functional queues.
Issues with the naive strategy and other solutions ... things to think about:
What happens if you make a new request while the old one has not yet completed?
What happens if an error occurs? Do you want errors inline? You can use another queue for errors?
Do you want retries?
What happens if a message is lost? (i.e. a request was pushed, but no response comes in...)? There are transactional queues etc.
Sample Code
object oLock = new object();
Queue<string> requests = new Queue<string>();
Queue<string> responses = new Queue<string>();
Thread mThread;
AutoResetEvent mEvent = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
mThread = new Thread(ProcessingEngine);
mThread.IsBackground = true;
mThread.Start();
}
private void ProcessingEngine()
{
string result;
string request = null;
while (true)
{
try
{
mEvent.WaitOne();
lock (oLock)
{
request = requests.Dequeue();
}
var wc = new WebClient();
result = wc.DownloadString(request);
lock (oLock)
{
responses.Enqueue(result);
}
}
catch (Exception ex)
{
lock (oLock)
{
responses.Enqueue(ex.ToString());
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (oLock)
{
//Stick in a new request
requests.Enqueue("http://yahoo.com");
//Allow thread to start work
mEvent.Set();
//Check if a response has arrived
if (responses.Any())
{
var result = responses.Dequeue();
listBox1.Items.Add(result.Substring(1,200));
}
}
}
}
If you use System.Windows.Forms.Timer instead of System.Threading.Timer, your Tick handler will be called from Form's message loop and you'll have full access to all controls - it will be safe to call bgWorker.RunWorkerAsync(). As for retrieving results - RunWorkerCompleted is also called from message loop thread and you can safetly update your UI here.
The solution is simple - INVOKE back into the main thread. THere is an Invoke method on the winform control. This will basically change threads for execution to the UI thread, and allow you to manipulate the UI.
Do that "block" (i.e. not once per control but once when you have news).

Add content asynchronously (threading + ajax)

Ok what id like to do is to load a page that displays 90% of content, and load the last 10% asynchronously.
As im rendering the page i programatically create an update panel which i pass to a thread. When this thread finishes it then updates the updatepanel on the main thread.
public void test(object parameter)
{
Thread.Sleep(2000);
var updpanel = (UpdatePanel)parameter;
updpanel.ContentTemplateContainer.Controls.Add(new LiteralControl("HI"));
updpanel.Update();
}
protected void Page_Load(object sender, EventArgs e)
{
var th = new Thread(new ParameterizedThreadStart(test));
var updpanel = new UpdatePanel() { UpdateMode = UpdatePanelUpdateMode.Conditional };
ContentPlaceHolder1.Controls.Add(updpanel);
th.Start(updpanel);
}
Failing this, in a single threaded approach, do i just keep polling the page to see if it has finished or not?
One thing to keep in mind is, even though ASP.Net development seems like it's closely related to windows development, there's a big difference: your code to handle a request, most of the time, is executed in a fraction of a second and done... In this example, once the main thread has completed, the generated page has already been sent to the requestor, leaving your secondary thread running in the background of your server, working on a page that has already been sent out.
What you'll probably need to do is generate the 90% of the page, and then send it out. On your page, you will need to use ajax to, on page load (for the client), request the other 10% from the server... You'll probably want to do the javascript with a library like jquery, and on the server end setup a web service to handle the requests.
You cannot use threading this way on the server. Your second thread will probably not complete until after the page have been processed and the request lifecycle is complete.
Depending on what you are trying to achieve: do you need to process data in parallel server-side you should look into Asynchronous Pages in ASP.Net 2.0.
Another approach would be to render the page ("90%" as you call it) and use ajax on the client to request additional data.

Categories

Resources