I want to create a thread on user_login Event or Form_load Event.
In this thread i want to call a class function to execute some sql statement, and the user do not have to wait for the result or background process to be finished, he is just directed to his desired page let say my profile or what ever.
I am using ASP.NET, C#.
For what it is worth, this is a Bad Idea. There are a variety of ways that that IIS could terminate that background thread (IIS restart, app pool restart, etc., all of which are normal expected behavior of IIS), and the result would be that your DB transaction gets silently rolled back.
If these queries need to be reliably executed, you should either execute them in the request or send them to a windows service or other long-lived process. This doesn't mean that the user can't get feedback on the progress- the IIS request itself could be executed via an AJAX call.
Here are some examples of asynchronous calls in C#.
http://support.microsoft.com/kb/315582
The choice of pattern depends on your needs. Note that in sample 5 you can provide null as the callback if you don't want any code executed when the action is done.
You could do this by calling your method in a thread using Thread.Start. IsBackground is false by default, which should prevent your application from stopping.
http://msdn.microsoft.com/en-us/library/7a2f3ay4.aspx
But, since most of your time will probably be spent in your database call. Why not just execute it asynchronously without a callback? On a SqlCommand that would be BeginExecuteNonQuery.
Related
I am writing an API using ASP.NET and I have some potentially long running code from the different end points. The system uses CQRS and Event Sourcing. A Command comes into to an end point and is then published as an event using MediatR. However the Handlers are potentially long running. Since some of the Requests coming in might be sent to multiple Handlers. This process could take longer than the 12s that AWS allows before returning an Error code.
Is there a way to return a response back to the caller to say that the event has been created while still contining with the process? That is to say fire off a separate task that performs the long running piece of code, that also catches and logs errors. Then return a value back to the user saying the Event has been successfully created?
I believe that ASP.NET spins up a new instance each time a call is made, will the old instance die one a value is returned, killing the task?
I could be wrong with a number of points here, this is my knowledge gleaned from the internet but I could have missunderstood articles.
Thanks.
Yes, you should pass the long-running task off to a background process and return to the user. When the task is complete, notifiy the user with whatever mechanism is appropriate for your site.
But do not start a new thread, what you want is to have a background service running for this, and use that to manage your request.
If a new thread is running the long operation it will remain “open/live” until it finishes. Also you can configure the app pool to always be active.
There are a lot of frameworks to work with long running tasks like Hangfire.
And to keep the user updated with the status of the task you can use SignalR to push notifications to the UI
I have an application written in Delphi using TClientSocket that is sending data to another application written in C#. For many reasons, the C# application is slow to respond, blocking my Delphi application and not respecting the time-out I have set.
My Delphi application reads responses like this:
Sock.Socket.ReceiveText
This causes the application to wait for a response. But if I do this instead, the application waits and respects the time-out:
while not receiveData do
begin
if Sock.Socket.ReceiveLength > 0 then
begin
receiveData := True;
end;
Inc(Cont);
Sleep(100);
if (Cont > 10) then
raise Exception.Create('Timeout');
end;
My Delphi app sends two requests. The first one times out, but C# is still processing it. My Delphi app then sends the second request, and this time C# sends the response for the first request.
Will the second request receive data for the first request? Or, when I timeout in Delphi, will they cross information?
Once your Delphi code times out, it forgets about the first request, but your C# code does not know that. Since you are not dropping the connection, the second request will indeed receive the response data for the first request. By implementing timeout logic and then ignoring the cause of the timeout, you are getting your two apps out of sync with each other. So, either use a longer timeout (or no timeout at all), or else drop the connection if a timeout occurs.
As for your Delphi app freezing, that should only happen if you are using the TClientSocket component in blocking mode and performing your reading in the context of the main UI thread. You should not be using blocking mode in the main UI thread. Either:
Use TClientSocket in non-blocking mode, do all of your reading in the OnRead event only, and do not read more than ReceiveLength indicates.
Use TClientSocket in blocking mode, and do all of your reading in a worker thread, and then signal the main UI thread only when there is data available for it to process (better would be to process the data in the worker thread, and only sync with the main thread when making UI updates).
I am developing a web-api that takes data from client, and saves it for later use. Now i have an external system that needs to know of all events, so i want to setup a notification component in my web-api.
What i do is, after data is saved, i execute a SendNotification(message) method in my new component. Meanwhile i don't want my client to wait or even know that we're sending notifications, so i want to return a 201 Created / 200 OK response as fast as possible to my clients.
Yes this is a fire-and-forget scenario. I want the notification component to handle all exception cases (if notification fails, the client of the api doesn't really care at all).
I have tried using async/await, but this does not work in the web-api, since when the request-thread terminates, the async operation does so aswell.
So i took a look at Task.Run().
My controller looks like so:
public IHttpActionResult PostData([FromBody] Data data) {
_dataService.saveData(data);
//This could fail, and retry strategy takes time.
Task.Run(() => _notificationHandler.SendNotification(new Message(data)));
return CreatedAtRoute<object>(...);
}
And the method in my NotificationHandler
public void SendNotification(Message message) {
//..send stuff to a notification server somewhere, syncronously.
}
I am relatively new in the C# world, and i don't know if there is a more elegant(or proper) way of doing this. Are there any pitfalls with using this method?
It really depends how long. Have you looked into the possibility of QueueBackgroundWorkItem as detailed here. If you want to implement a very fast fire and forget you also might want to consider a queue to pop these messages onto so you can return from the controller immediately. You'd then have to have something which polls the queue and sends out the notifications i.e. Scheduled Task, Windows service etc. IIRC, if IIS recycles during a task, the process is killed whereas with QueueBackgroundWorkItem there is a grace period for which ASP.Net will let the work item finish it's job.
I would take a look on Hangfire. It is fairly easy to setup, it should be able to run within your ASP.NET process and is easy to migrate to a standalone process in case your IIS load suddenly increases.
I experimented with Hangfire a while ago but in standalone mode. It has enough docs and easy to understand API.
I'm trying to implement a functionality where there is a stored procedure on SQL Server that has to be called from ASP MVC application and processed on the background (it might take long since it calls another stored procedure remotely to process an excel file stored on a server). But the response of the last HTTP request should be returned back to client so the UI will not be hanging waiting for processing.
I have tried so many different ways but UI is still not responding right away.
I tried BackgroundWorker but it's not allowing the main thread to response back to client until its done processing,
also I tried:
Thread.QueueUserWorkItem(delegate { //method which performs stored procedure calls//
});
It still not returning response and HttpContext.Current not available in background thread.
Maybe there is a way to start background processing, pause it for letting main thread to return response to browser and then resume background thread to make all processing with stored procedure calls?
Am I missing something?
Could someone please give an idea how I can solve this problem? Would be much appreciated.
What I ended up with and it works fine in my case. I'm not sure about efficiency, but it perfectly works. So, the code which makes calls to a stored procedure I put on a separate thread, so that the main thread is finished while the processing off background calls is happening on a separate thread and finishes successfully after some period of time. At the same time UI is available so user can make another request which will also be processed the same way. I tested three requests. One after another overlapping, meaning that while first request was being processed on the background I submitted another one and yet another one. UI was responding immediately and all the work was done.
// ...main thread is working here
//put a call to stored procedure on a separate thread
Thread t = new Thread(()=> {
//call stored procedure which will run longer time since it calls another remote stored procedure and
//waits until it's done processing
});
t.Start();
// ...main thread continue to work here and finishes the request so it looks for user as the response is coming right away, all other stuff is being processed on that new thread so user even doesn't suspect
I shall quote Stephan Clearys great article:
When you use async on the server side (e.g., with ApiController), then you can treat each web request as an asynchronous operation. But when you yield, you only yield to the web server thread pool, not to the client. HTTP only allows a single response, so the response can only be sent when the request is fully complete.
Basically, this doesn't adhere to the HTTP protocol, where each request has only one response.
This can be achieved using multiple calls to the ASP.NET service, where a request returns a unique ID immediately, which the client can query multiple times for progress. You may look into SignalR for help with such an implementation:
What is SignalR and "real-time web" functionality? It's the ability to have your server-side code push content to the connected clients as it happens, in real-time.
There is part1 and part2 article by Dino Esposito outlines a way to achieve your polling using a client side timer and controller actions. You would basically serialize access to a progress worker controller method that returns task status and completion data. However, it may be a little chatty if you are only going to be performing one or two long running processes.
If the response to the client does not depend on the result of the background process (i.e. run the process in the background and don't have the UI waiting for it), then you could use Revalee (an open-source tool) to perform the background task.
The UI will request this route...
public class ForegroundController : Controller
{
public ActionResult InitiateBackgroundTask()
{
// The absolute URL that will be requested on the callback.
var callbackUri = new Uri("http://localhost/BackgroundTask/Callback");
// The information that will be needed to initiate the background task.
object state = "Any object";
this.CallbackNowAsync(callbackUri, state)
// ... your controller will now return a response to the browser
return View();
}
}
Background work will be executed in this controller...
public class BackgroundTaskController : Controller
{
[AllowAnonymous]
[HttpPost]
[CallbackAction]
public ActionResult Callback(Guid callbackId, object state)
{
// Perform the background work
// ... insert your background task code here ...
// Return a status code back to the Revalee Service.
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
}
Revalee Project Site
I am creating a Windows Service app that I would like to have programmatically pause when either a system error, odbc connection, or missing file error occur while . I was wondering if anyone knows how to do this? The Windows service app uses an odbc connection and datareader to connect to an MS Access database and an Oracle table, so there are the probable errors that I would be handling with those, I just want to allow a pause for the user handle the errors if/when they occur.
ServiceController service = new ServiceController(serviceName);
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutValue);
service.Pause(); //or whatever you want here.
sevice.WaitForStatus(ServiceControllerStatus.Paused, timeout);
...
Then to restart, do the same thing except for
service.Continue();
sevice.WaitForStatus(ServiceControllerStatus.Running, timeout);
You can do this for any state you want. Check out the msdn documentation by googling SeviceController. It will be the first result returned.
Also, you will need to handle the OnPause and OnContinue events in your service.
Have you tried?
System.Threading.Thread.Sleep(1000); // sleep for 1 second
Adjust the 1000 to 1000 times however long you want it to sleep in seconds.
Assuming that your service has a continual loop that checks for data, add a check to an external source for pause/continue commands. This source can be a message queue like MSMQ or a database table.
I implemented something along like this by having my service continually check a table for commands, and reporting its status in another table. When it gets a start command it launches a processing loop on another thread. A stop command causes it to signal the thread to gracefully exit. The service core never stops running.
The user interacts via a separate app with a UI that lets them view the service's status and submit commands. Since the app does its control via a database it doesn't have to run on the same machine that the service is running on.