I have an issue with using a Database in a thread in my asp.net Application.
When I want to start my application I want to start a thread called "BackgroundWorker" with it, which runs in the background till the whole application is stopped.
The problem is that I have massive problems with the dbContext in the thread.
I I try to start the walker in my Startup.cs in the methods "ConfigureServices" or "Configure" and then initialize the dbContext in the constructor in the Walker like this "dbContext = new ApplicationContext()" it tells me that the connection is not configured, when I try to operate in the while(true) queue on the database.
If I write an own Controller for the Walker which receives a ApplicationContext in his constructor and then starts a Thread like this, if i call this controller once with a GET Request:
public BackgroundWorker(ChronicusContext dbContext)
{
_dbContext = dbContext;
_messageService = new MailMessageService();
}
// GET: api/backgroundworker
[HttpGet]
[Route("start")]
public void StartWorker()
{
//Thread thread = new Thread(this.DoBackGroundWork);
Thread thread = new Thread(() => DoBackGroundWork(this._dbContext));
thread.Start();
}
public void DoBackGroundWork(ChronicusContext _dbContext)
{
while (true)
{
if (_dbContext.PollModels.Any()) //Here is the exception
{
...
}
}
}
Then I receive an System.ObjectDisposedException that the object is already disposed inside the while (true) queue.
I tried those and similar things in many different ways but allways receive exceptions like these two or that the database connection is closed.
Can somebody help me and tell me, how this works?
Thank you!
Generally, server side multithreading for Web Applications does not happen often and is, most times, a huge no no.
Conceptually, your server is "multithreaded", it handles many HTTP requests from clients/users/other servers. For mobile and web architecture/design, your server(s) process multiple requests and your clients are handling asynchronous calls and dealing with waiting for responses from long running calls like your API method StartWorker.
Think of this scenario, you make a request to your WebAPI method StartWorker, the client, making the request is waiting for a response, putting the work on another thread does nothing as the client is still waiting for a response.
For example, let's consider your client an HTML web page with an Ajax call. You call StartWorker via Ajax, you will be loading data into a HTML table. You will desire, from a UX perspective, to put up a progress spinner while that long running StartWorker responds to your HTML Page Ajax call request. When StartWorker responds, the Ajax call loads the HTML table with the StartWorker response. StartWorker has to respond with the data. If StartWorker responds beforehand than you will have to send a push notification, via SignalR, for example, when the other thread completes and has the data you need for the HTML table.
Hopefully, you see, the call to the WebAPI method, takes the same amount of time from a Ajax request/response perspective, so multithreading becomes pointless in this scenario, a most common web application scenario.
You can have your client UI load other UI elements, showing a progress spinner in HTML table UI area, until your database call is complete and responds with the data to your Ajax call. This way your users know things are happening and something is still loading.
If you still need your additional thread in your API for your project needs, I believe you have to be using Entity Framework 6 or greater to support asynchronous queries, see this tutorial:
http://www.codeproject.com/Tips/805923/Asynchronous-programming-in-Web-API-ASP-NET-MVC
UPDATE
Now that I know you need to run a SQL query on a repeating frequency of time, and you have an Azure Web App, what you want to use is Azure Automation if you are using Sql Azure or create a Sql Server Job if you are using a Sql Server instance as your backend
DbContext is not thread safe. You need to create a new context from inside your thread.
public void DoBackGroundWork()
{
ChronicusContext anotherContext= new ChronicusContext();
while (true)
{
if (anotherContext.PollModels.Any())
{
...
}
}
}
Related
I am running a long running function as background task in my asp.net application. Before the task completes the main thread exits (I want it that way only, since if I use the await keyword and make main thread wait till background task completes, I get proxy error with message
Proxy Error
The proxy server received an invalid response from an upstream server since the background task is too long
But once after the task completion neither I am able to refresh the page by redirecting to the same page or neither I am able to override the UI. Is there any way to update UI after main thread completes execution.
My code goes like this:
protected void btnImport_Click(object sender, EventArgs e)
{
var task = ImportThread();
if (task.IsCompleted)
{
DisplaySuccess("Import success");
}
else
DisplayError("Import failed");
}
private async Task<bool> ImportThread()
{
try
{
var success = await Task<bool>.Run(() => new Manager().Import().ConfigureAwait(false);
if (task.IsCompleted)
{
DisplaySuccess("Import success");
}
else
{
DisplayError("Import failed");
}
return true;
}
The above async task awaits the method below which is present in another class.
public bool Import()
{
// some operations here
return true;
}
After this method completes the control return backs to ImportThread() but the code written there to override UI is not updating UI. I need to update UI with the status of import. And also from ImportThread control is not going back to button click event method too.
Please help me with any way to update UI the status of import.
Note: I tried using Redirect.Response in ImportThread() to refresh the page, but that didn't work
Your problem is that you have to grasp and under stand the web page lifecycle here.
You have this case in which the web page is sitting on the users desktop:
Now say the user clicks a button.
You now have this:
var task = ImportThread();
if (task.IsCompleted)
Ok, so the web page is up on the server. You can put in even async awaits until the cows come home, but you STILL HAVE THIS:
So as long as your code runs, or waits, the web page is STILL STUCK UP on the server side. ONLY until code completes and exits does the page travel down to the client side.
AGAIN:
Your code behind cannot halt, and cannot wait for something to finish, since if it does, then the page REMAINS up on the server until processing finished.
THEN AND ONLY THEN does the web page make the trip back down to the client side. This then occurs;
And then the SERVER SIDE PAGE IS TOSSED OUT of memory, and all class variables are DESTROYED!!! The web server is now waiting for ANY USER to post back a page for processing!!
So, if you need to run some kind of long running process?
You have a few choices:
post the page, code behind runs, code behind starts a NEW thread, web page makes trip back to client side. At that point, you need a timer + some type of web method call (ajax) to poll or ask the server if the long running process is done. And since a ajax call does NOT have use of any web controls on that page, or page class variables (remember, AFTER the web page travels down back to client side, the web page is NOT NOT EXISTING web server side in memory, nor is ANY of the class variables existing). So, again, this quite much means some kind of timer, or as noted, a timer + code to call some ajax method. and that long running process will have to VERY likely use session() since you don't have use of controls, or even ViewState.
And you don't necessary have to use a ajax call. You could use a simple JavaScript client side routine with a timer that say clicks a button every 1 or 2 seconds, the code behind runs, and it would then have to get the status of that long running process (again probably from session), and then update the display. And then you could also include code to stop the timer when the status has changed to "done" or whatever.
So code behind does not and will not "update" the web page multiple times. You have ONE round trip, and the code behind must run fast, must finish running, and can't even use a AWAIT command, since then the page will STLL wait, and STILL be stuck up on the server.
If you want to go beyond the simple timer trick approach - which I often use?
Then you need to adopt and introduce into your web site something designed for this type of case -
Thankfully, there is signalR for this purpose, and that no doubt the best option and approach for you, since it is designed for exactly your question and scenario.
SignalR
https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr#:~:text=What%20is%20SignalR%3F%20ASP.NET%20SignalR%20is%20a%20library,process%20of%20adding%20real-time%20web%20functionality%20to%20applications.
If you want to asynchronously notify a user (of completion or failure of anything such as a task), you can use web push notification (using firebase messaging cloud) or SignalR sockets. When you use a background task you lose the main thread and unfortunately, there is no way to respond to the related user.
I have an ASP.NET Core Web API project. That has one controller with a method called GetLocations
GetLocations connects to 5 other web services on the internet. Gathers some info and return a collection via json. In this method I am caching the data every 5 mins using In Memory caching.
If the cache expires, it tries to connect to all 5 services and get the info and so on.
My problem is:
I have a lot of users requesting this data constantly, 50 requests a second to this API.
When the cache expires I believe there is some kind of thread locking. I have limited visibility into the project at the moment but I suspect that all these requests are calling the method and reaching out to the 5 dependent services until one of them gets a completed response from all 5.
Is my assumption right? If so how can I go about fixing this? Will I need to make each call to the web services async? Will that help this scenario? I am not 100% sure because the requests are what triggers the method call.
You should definitely make the calls to the external services use Async / Await.
That's just a given - as the best practice is to always use async for I/O heavy operations (such as calling a third-party service).
Now, you should also create a class that manages these calls. You can add it as a Singleton in your IoCConfig. In that class, make sure you're "locking" to avoid the issue you just described and not call the underlying services numerous times while the cache is being built.
Check here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
You are facing this issue because of following reason.
You are using Cache and it will expire at some definite time.
After Cache expire you call external web service method to collect the data. Now at this point of time it might happen that other request in queue get choose for execution.
Once that another request is chosen for execution it also end up checking cache and it now data in cache then execute external service and so on for other request.
Solution to this.
First Check cache contains data or not.
If Not create lock so following section only be executed by single thread.
Now in that lock section again check for cache and if cache contains data then simply return but it does not contains then call external service.
At this point of time if another thread get selected for execution then it has to wait for execlsive section to complete its works.
Once that section get completed it store data in cache and so after if any queued or new request is there it choose data from cache.
Note : It should something like this.
public List<string> GetData()
{
if(Cache[key] == null)
{
lock(obj) // obj should be static
{
if(Cache[key] == null)
{
// Load data from service
Cache[key] == data;
}
}
}
return (List<string>)Cache[Key];
}
I have a C# web application that makes a web service call, then renders a page for a browser. Following this advice, I chose to use System.Net.WebClient for the request because it had a succint interface and all the control I needed.
WebClient offers me async versions of all the download methods. Should I use them? I don't care if the current user waits. I need the web service result before I can render the page, and I have nothing else to be doing (for her) in the meantime. However I really do care if my server is tied up while one user's web service call completes. If this was javascript, a synchronous web request on the main thread would hold up at least the whole window. Is this the case in asp.net? For reasons outta my control, my web service request is at the bottom of a pile of 15 method calls. Dot I have to convert them all to async to see any advantage?
Generally speaking, async IO won't yield faster per-request response, but in theory it can increase throughput.
public async Task<IActionResult> YourWebApiMethod() {
// at this point thread serving this request is returned back to threadpool and
// awailable to serve other requests
var result = await Call3ptyService();
// once IO is finished we grab new thread from thread pool to finish the job
return result;
}
// thread serving this request is allocated for duration of whole operation
public IActionResult YourWebApiMethod() {
return Call3ptyService().Result;
}
You have only so-many threads in thread pool, if every single one is busy waiting for external service; your web server will stop serving requests. As for your particular problem - try it and you'll find out.
I have a loop that actually waits for some process for completion of a Job and returns result.
I have MyRestClient.FetchResult(id) and MyRestClient.FetchResultAsync(id) both available to me, which fetches result from some remote service and returns boolean value if it is complete.
public class StatusController: ActionController {
public ActionResult Poll(long id){
return new PollingResult(()=>{
return MyRestClient.FetchResult(id) == SomethingSuccessful;
});
}
}
public class PollingResult : ActionResult{
private Func<bool> PollResult;
public PollingResult(Func<bool> pollResult){
this.PollResult = pollResult;
}
public override void ExecuteResult(ControllerContext context)
{
Response = context.HttpContext.Response;
Request = context.HttpContext.Request;
// poll every 5 Seconds, for 5 minutes
for(int i=0;i<60;i++){
if(!Request.IsClientConnected){
return;
}
Thread.Sleep(5000);
if(PollResult()){
Response.WriteLine("Success");
return;
}
// This is a comet, so we need to
// send a response, so that browser does not disconnect
Response.WriteLine("Waiting");
Response.Flush();
}
Response.WriteLine("Timeout");
}
}
Now I am just wondering if there is anyway to use Async Await to improve this logic because this thread is just waiting for every 5 seconds for 5 minutes.
Update
Async Task pattern usually finishes all work before sending result back to client, please note, if I do not send intermediate responses back to client in 5 seconds, client will disconnect.
Reason for Client Side Long Poll
Our web server is on high speed internet, where else clients are on low end connection, making multiple connections from client to our server and then relaying further to third party api is little extra overhead on client end.
This is called Comet technology, instead of making multiple calls in duration of 5 seconds, keeping a connection open for little longer is less resource consuming.
And of course, if client is disconnected, client will reconnect and once again wait. Multiple HTTP connections every 5 seconds drains battery life quicker compared to single polling request
First, I should point out that SignalR was designed to replace manual long-polling. I recommend that you use it first, if possible. It will upgrade to WebSockets if both sides support it, which is more efficient than long polling.
There is no "async ActionResult" supported in MVC, but you can do something similar via a trick:
public async Task<ActionResult> Poll()
{
while (!IsCompleted)
{
await Task.Delay(TimeSpan.FromSeconds(5));
PartialView("PleaseWait").ExecuteResult(ControllerContext);
Response.Flush();
}
return PartialView("Done");
}
However, flushing partial results goes completely against the spirit and design of MVC. MVC = Model, View, Controller, you know. Where the Controller constructs the Model and passes it to the View. In this case you have the Controller is directly flushing parts of the View.
WebAPI has a more natural and less hackish solution: a PushStreamContent type, with an example.
MVC was definitely not designed for this. WebAPI supports it but not as a mainstream option. SignalR is the appropriate technology to use, if your clients can use it.
Use Task.Delay instead of Thread.Sleep
await Task.Delay(5000);
Sleep tells the operating system to put your thread to sleep, and remove it from scheduling for at least 5 seconds. As follows, the thread will do nothing for 5 secs - that's one less thread you can use to process incoming requests.
await Task.Delay creates a timer, which will tick after 5 seconds. The thing is, this timer doesn't use a thread itself - it simply tells the operating system to signal a ThreadPool thread when 5 seconds have passed.
Meanwhile, your thread will be free to answer other requests.
update
For your specific scenario, it seems there's a gotcha.
Normally, you'd change the surrounding method's signature to return a Task/Task<T> instead of void. But ASP.NET MVC doesn't support an asynchronous ActionResult (see here).
It seems your options are to either:
move the async code to the controller (or to another class with an async-compatible interface)
Use a WebAPI controller, which seems to be a good fit for your scenario.
I have a video encoding in process with third party cloud api, however
my web client (chrome/ie/ff) need to poll result of encoding. If I
simply pass on result for every 5 seconds, web client will need to
make multiple HTTP calls one after another
I think the approach when you're trying to poll the result of the video encoding operation within the boundaries of a single HTTP request (i.e., within your ASP.NET MVC controller method) is wrong.
While you're doing the polling, the client browser is still waiting for your HTTP response. This way, the client-side HTTP request may simple get timed out. It is also a not-so-user-friendly behavior, the user is not getting any progress notifications, and cannot request the cancellation.
I've recently answer a related question about long-running server side operation. IMO, the best way of dealing with it is to outsource it to a WCF service and use AJAX polling. I also answered another related question on how to do the asynchronous long-polling in a WCF service.
My Asp.net application generates a dynamic pdf. Sometimes this takes a while and is a quite heavy process. Actually i dont want my users to wait for the pdf, just send it to there mail after it generated.
So I tried a webservice. I'm passing an id (to get the data from the database) and some strings to the websercice's method.
But also with a webservice (even with asynchronous calls) the client only receives its response after the pdf is generated. So the user still has to wait.
So I'm kinda stuck, there must be a way i'm overlooking.
You don't need a webservice in order to get the ability to make asynchronous invocations.
You can just use ThreadPool.QueueUserWorkItem() as a fire-and-forget approach in the ASPX page, then return a reply with some sort of "work item id" - like a receipt or an order number.
Generate the PDF in the WaitCallback you pass to QUWI.
when the pdf is ready, that WaitCallback can send an email, or whatever.
Use a webservice if you want the function to be accessible, outside the webpage. Don't use it strictly for asynchrony.
Issue is that in your ASP.NET page code, you must be invoking the web service synchronously so the page waits till web service returns. You should try invoking the web service asynchronously (or on the different thread) and then don't wait for it to complete. Typically, visual studio generated proxy already has asynchronous overloads that you may use.
Alternately, you may modify your web service code - essentially, when request to your web method comes, you can start PDF generating on a different thread so that your web method may end indicating your client (page in this case) that request has been successfully scheduled for processing.
there are two ways which i know
First ways;
In asp.net code behind (in xxx.aspx.cs file) you can define a void method then you can call the method by starting a thread like below.
protected void SenMail(object prms)
{
int id = int.Parse(prms.ToString());
//mail sending proces
}
//starting SendMail method asynchronous
Thread trd = new Thread(SenMail);
trd.Start(idValue);
Second way;
You can create and mail sender page like "SendMail.aspx", then you can make an ajax request in javascript and no need to wait any response. you can pass id value to aspx page as request parameter.