In my web application, I have a page which is just for displaying purpose. After verifying the data, users can download the reports, which is taking around 2 - 3 minutes of time. I need to reduce this time taken. So, I thought of starting the report generation once the page is called, to share the time, without affecting the Page Load. I tried executing the report generation method simultaneously by using Task.Factory.StartNew() in my Page Load. The thing is that, I am able to execute the method as I expected. But, it shows the page, only when report generation is completed, even though page load event is over. Is it possible to force the page to be shown, once the page load is completed, and continue the report generation process in behind? Here is my code,
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
// page load condition checks
Task.Factory.StartNew(() => GenerateReports(), CancellationToken.None,
TaskCreationOptions.None, TaskScheduler.Default);
//
}
}
Does this give u same results?
Task GenReport = Task.Run (() =>
{
GenerateReports();
});
Edit: Try putting it in a new method and calling the method from pageload
Edit2: As Aron suggested dont use task run. I was just trying to help with what I knew in c# not asp. If I think further about it.. it can probably overload your server if client hit refresh too many times, that would create multiple tasks...
Related
In my C# controller, I kicked off an async task (using Task.Run), then redirect to a different page. My goal was to have the page fully loaded while the async task was running in the background. There will be a javascript code keep pinging web server to see if the job is done. However, what I noticed was that the code executes the redirect line before executing the loading in the async thread which is good. However, my page didn't start to load until the async thread is finished (even after redirect line finishes executing).
I tried
Task.Run(() => someLoadingCode());
HostingEnvironment.QueueBackgroundWorkItem(a => someLoadingCode());
new Thread(() => someLoadingCode()) { IsBackground = true }.Start();
but none of them works.
This is my code:
public void Controller()
{
Task.Run(() => someLoadingCode());
Response.Redirect(url);
}
Since someLoadingCode can take 10 minutes, I wanted it to redirect to my new page while it's loading in background. User may even be able to click away and go to another page after redirecting. But now it won't load my new page before someLoadingCode is finished.
I have a requirement where a client makes a request to a single web page, this web page needs to retrieve the results from two other web pages.
The two web pages that we are requesting info from carry out a process before returning the result, this process can take a few minutes so rather than starting a web request and waiting for it to return and then starting another I want to fire off both requests in background workers and have the results being generated in parallel.
So my code looks something like this (Pseudo code):
var worker1 = new BackgroundWorker();
var worker2 = new BackgroundWorker();
worker1.DoWork += (s, e) => {
//Web Request done here
};
worker2.DoWork += (s, e) => {
//Web Request done here
};
worker1.RunWorkerAsync();
worker2.RunWorkerAsync();
//Some logic here that basically waits for both to return.
Now I noticed that the results were still taking longer to return than I expected so I did a bit of a test and changed the contents of the Dowork to
using (var sw = new StreamWriter(#"c:\temp\TEST\Worker1.txt"))
{
for (int i = 0; i < 1000000; i++)
{
sw.WriteLine($"{i} - {DateTime.Now.ToLongTimeString()}");
}
}
For brevity I wont copy this back out but assume that the file name is changed to worker2.txt in the second workers DoWork()
Its crude I know, but it works, its takes about 3 seconds to write out the time 1 million times so in the first file I see times ranging from Execution Time to Execution Time + 3 seconds
In the second file I can see times ranging from Execution time + 3 Seconds to Execution Time + 6 seconds.
So it’s clear at this point that one worker is being executed first and then the other, but I cannot see why.
More info about the project - Web forms (This is a requirement I have been given and have to stick to) .net 4.5
**Edited to add : **
After coming back to this problem I have had a look at the pages that I am calling and notice that they have aspcompat=true in the page declaration, which I assume is what is causing the issue (They require this, I cant remove it).
What are my options now? Ideally I want to be able to call these pages to run in parallel, is there any way to still achieve this with the aspcompat set to true?
Editing for future readers
Note that the problem that I described above and the code that was provided were correct, the issue that I had was that the pages that I was calling were set to use ASPCOMPAT which forces webforms to work in STA mode which is what was throwing me off.
In the end the code above did work unchanged, the solution was to put the page with the background workers in a separate web application with its own app pool, that page the n used the background workers to call off to the pages running in aspcompat mode in their application pool - its not ideal, but its what we wanted for the live deployment anyway.
You could skip the BackgroundWorker and use Task.WaitAll() instead.
void Main()
{
Task.WaitAll(FirstRequest(), SecondRequest());
}
// Define other methods and classes here
private async static Task FirstRequest()
{
// Do your work for one of the WebRequests here
await Task.Delay(3000);
Console.WriteLine("Done with 1");
}
private async static Task SecondRequest()
{
// Do your work for the second WebRequest here
await Task.Delay(3000);
Console.WriteLine("Done with 2");
}
i'm in trouble. In my web app i have a code that creates a thread on the Click event of a button to perform a data intensive task, the is like this:
protected void button_Click(object sender, EventArgs e)
{
// Show loader image
loader.Show();
// Creating the thread
System.Threading.ParameterizedThreadStart ts = new System.Threading.ParameterizedThreadStart(RunThread);
Thread t = new Thread(ts);
t.Name = "BackgroundThread";
t.Priority = ThreadPriority.AboveNormal;
t.Start(HttpContext.Current);
}
private void RunThread(object state)
{
// Setting the current thread property as the background thread
CurrentThread = Thread.CurrentThread;
if (IsThreadRunning(CurrentThread))
{
CurrentThread.Join(TimeSpan.FromMinutes(6d));
}
// DO SOME HEAVY STUFF
}
In the button click i show the loader. The problem is: Even calling Join in the BackgroundThread, the Page_Load event gets called frequently making the page refresh. In other words, while the RunThread doesn´t finish, the Page_Load is getting called. Could i prevent this from happening?
OBS: What i wanna do is: show the loader while the data intensive thread is running without make repetitive refreshs on the page.
The only way to check long running task status from web page without polling (making postback from time to time) is to use Web Sockets, but i'm pretty sure using it would be big overhead for this kind of tasks.
I would use ajax requests to prevent full page reload.
Seems like you need to read more about the whole web request and response process.
I have an ASP.NET page that requires data from another DLL and the process might take a long time. So, I set out to use APM. But when I try that, the page just never stops loading. It loads indefinitely. Is there something I'm doing wrong?
Here is my web page:
List<string> allVoices;
GetAllVoicesDelegate getVoicesDelegate;
internal delegate List<String> GetAllVoicesDelegate();
protected void Page_Load(object sender, EventArgs e)
{
Page.AddOnPreRenderCompleteAsync(new BeginEventHandler(BeginGetDropDownValues),
new EndEventHandler(EndGetDropDownValues));
}
public IASyncResult BeginGetDropDownValues(object o,EventArgs args,AsyncCallback cb,object obj)
{
getVoicesDelegate = MyLib.getStrings;
return getVoicesDelegate.BeginInvoke(EndGetDropDownValues,null);
}
public void EndGetDropDownValues(IASyncResult ar)
{
allVoices = getVoicesDelegate.EndInvoke(ar);
}
protected override OnPreRenderComplete(EventArgs e)
{
if(allVoices.Count>0)
{
foreach(String str in allVoices)
{
Response.Write(str);
}
}
base.OnPreRenderComplete(e);
}
Here is the MyLib.getStrings() method in another DLL:
public List<String> getStrings()
{
List<String> allStr=new List<string>();
allStr.Add("1");
allStr.Add("2");
allStr.Add("3");
allStr.Add("4");
}
If you have to get data from a long running process, making async calls from the web page won't help you because in the end, the process needs to finish before the page can finish rendering. Making async calls frees you to do other stuff in the mean time, but the page can't render until all the activity on it is finished.
I think you'll have to take a different approach, either using Ajax to poll the server until the response is ready, or creating an intermediate page that tells the user to wait until the process is complete. Once it's complete, the page refreshes and the user sees the data.
I'm not overly familiar with your approach to asynchronous computing in asp.net (I generally use ajax to make requests to web services, etc.)
One possible flaw, from my point of view is the OnPreRenderComplete handler. This handler is not asynchronous to the best of my knowledge. It is used to handle the event of when all page controls are loading and ready.
The OnPreRenderComplete method is called when the prerendering stage of the page life cycle is complete. At this stage of the page life cycle, all controls are created and the page is ready to render the output.
In this event handler, you are making reference to allVoices class-level member which is processed by the async handlers. Is it possible then the code in this handler has to wait for the async delegate to complete? (in essence defeating the purpose of async).
Again just a guess. What happens if you take out the `OnPreRenderComplete' handler? or comment out the code within?
Additionally - I think the article you referenced is a little outdated and may not apply to web application development? Generally asynchronous programming on the web is done via AJAX and/or Web services/WCF?
Most likely your problem is your ASP.NET page compiling (typically takes seconds), and not the dll loading (typically takes only a few milliseconds).
The code sample you have provided launches some work on a separate thread and allows the asp.net worker process to continue processing your page request without blocking on your long running task. If the long running task takes a long time to complete, then your page will take a long time to render.
Start by replacing the begin with some kind of mocked up code to return an invoice. If your page completes almost immediately, then your async wiring is correct and you probably need to move to some kind of polling approach which uses the first request to start the task and renders a "we are processing your request" page to the user. This page then uses ajax to poll the system for some kind of completion flag, once that is received, the user is redirected to the result page and the results are displayed.
I have an asynchronous operation that for various reasons needs to be triggered using an HTTP call to an ASP.NET web page. When my page is requested, it should start this operation and immediately return an acknowledgment to the client.
This method is also exposed via a WCF web service, and it works perfectly.
On my first attempt, an exception was thrown, telling me:
Asynchronous operations are not allowed in this context.
Page starting an asynchronous operation has to have the Async
attribute set to true and an asynchronous operation can only be
started on a page prior to PreRenderComplete event.
So of course I added the Async="true" parameter to the #Page directive. Now, I'm not getting an error, but the page is blocking until the Asynchronous operation completes.
How do I get a true fire-and-forget page working?
Edit: Some code for more info. It's a bit more complicated than this, but I've tried to get the general idea in there.
public partial class SendMessagePage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string message = Request.QueryString["Message"];
string clientId = Request.QueryString["ClientId"];
AsyncMessageSender sender = new AsyncMessageSender(clientId, message);
sender.Start();
Response.Write("Success");
}
}
The AsyncMessageSender class:
public class AsyncMessageSender
{
private BackgroundWorker backgroundWorker;
private string client;
private string msg;
public AsyncMessageSender(string clientId, string message)
{
this.client = clientId;
this.msg = message;
// setup background thread to listen
backgroundThread = new BackgroundWorker();
backgroundThread.WorkerSupportsCancellation = true;
backgroundThread.DoWork += new DoWorkEventHandler(backgroundThread_DoWork);
}
public void Start()
{
backgroundThread.RunWorkerAsync();
}
...
// after that it's pretty predictable
}
If you are running webforms set Ansync = "true" in your .aspx page where you are making the request. <%# Page Language="C#" Async="true" ... %>
If you don't care about returning anything to the user, you can just fire up either a separate thread, or for a quick and dirty approach, use a delegate and invoke it asynchrnously. If you don't care about notifying the user when the async task finishes, you can ignore the callback. Try putting a breakpoint at the end of the SomeVeryLongAction() method, and you'll see that it finishes running after the page has already been served up:
private delegate void DoStuff(); //delegate for the action
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
//create the delegate
DoStuff myAction = new DoStuff(SomeVeryLongAction);
//invoke it asynchrnously, control passes to next statement
myAction.BeginInvoke(null, null);
Button1.Text = DateTime.Now.ToString();
}
private void SomeVeryLongAction()
{
for (int i = 0; i < 100; i++)
{
//simulation of some VERY long job
System.Threading.Thread.Sleep(100);
}
}
OK, here's the problem: the Async attribute is for the case where your page is going to call some long-running task that also blocks the thread, and then your page needs the output from that task in order to return info to the user. For example, if your page needed to call a web service, wait for its response, and then use the data from the response to render your page.
The reason you'd use the Async attribute is to avoid blocking the thread. This is important because ASP.NET applications use a thread pool to serve requests, and there are only a relatively small number of threads available. And if each call ties up the thread while waiting on the web service call, then soon you're going to hit enough concurrent users that users are going to have to wait until these web service calls complete. The Async attribute lets the thread return to the thread pool and serve other concurrent visitors to your web site, rather than forcing it to sit still doing nothing while waiting for the web service call to return.
The upshot for you is this: the Async attribute is designed for the case where you can't render the page until the asynchronous task completes, and that's why it doesn't render the page immediately.
You need to launch your own thread, and make it a daemon thread. I don't remember the exact syntax for that, but you can easily find it in the doc by searching the BCL doc for "daemon". This means the thread will keep your application from shutting down while it is alive, which is important because ASP.NET and IIS reserve the right to "recycle your process" when they deem it necessary, and if that happens while your thread is working, your task will be stopped. Making the thread daemon will prevent this (except for some possible rare edge cases ... you'll find out more when you find the documentation on this).
That daemon thread is where you will kick off these tasks. And after you've told the daemon thread to do the task, you can immediately render your page ... so the rendering of the page will happen immediately.
Even better than a daemon thread in your ASP.NET process, though, would be to implement a Windows Service for doing the task. Have your ASP.NET application communicate the task to be performed to the Service. No need for a daemon thread and no need to worry about your ASP.NET process being recycled. How do you tell the Service to do the task? Perhaps through WCF, or perhaps by inserting a record into a database table that the Service polls. Or a number of other ways.
EDIT: Here's another idea, which I have used before for this very same purpose. Write the info about your task into an MSMQ queue. Have another process (maybe even on another machine) pull from that queue and do the time-consuming task. The job of inserting into a Queue is optimized to return as quickly as possible, so your thread won't block while the data you put in the Queue is sent across the wire or anything like that. It is one of the fastest ways to make note of the fact that a task needs to be done without waiting for that task to execute.
You can work around this limitation quite easily and without even setting Async to true.
public void Start()
{
new Task(() =>
{
backgroundThread.RunWorkerAsync();
}).Start();
}
If you get this error when calling web service asynchronously, make sure adding the Async='true' attribute as instructed by the
exception message?
top of the page < Page Language='VB' Async='true' AutoEventWireup='false'
CodeFile='mynewpage.aspx.vb' Inherits='mynewpage' %>