I use asynchronous XMLHttpRequest to call a function in ASP.net web service.
When I call an abort method on the XMLHttpRequest, after the server has received the request and processing it, the server continues processing the request.
Is there a way to stop the request processing on the server?
Generally speaking, no, you can't stop the request being processed by the server once it has started. After all, how would the server know when a request has been aborted?
It's like if you navigated to a web page but browsed to another one before the first one had loaded. That initial request will, at least to some extent (any client-side work will of course not take place), be fulfilled.
If you do wish to stop a long-running operation on the server, the service that is being invoked will need to be architected such that it can support being interrupted. Some psuedo code:
void MyLongRunningMethod(opId, args)
{
work = GetWork(args)
foreach(workItem in work)
{
DoWork(workItem)
//Has this invocation been aborted?
if(LookUpSet.Contains(opId))
{
LookUpSet.Remove(opId)
return
}
//Or try this:
if(Response.IsClientConnected)
{
HttpContext.Current.Response.End();
return;
}
}
}
void AbortOperation(opId)
{
LookUpSet[opId] = true
}
So the idea here is that MyLongRunningMethod periodically checks to see if it has been aborted, returning if so. It is intended that opId is unique, so you could generate it based on the session Id of the client appended with the current time or something (in Javascript, new Date().getTime() will get you the number of milliseconds since the epoch).
With this sort of approach, the server must maintain state (the LookUpSet in my example), so you will need some way of doing that, such as a database or just storing it in memory. The service will also need to be architected such that calling abort does not leave things in a non-working state, which of course depends very heavily on what it does.
The other really important requirement is that the data can be split up and worked on in chunks. This is what allows the service to be interruptable.
Finally, if some operation is to be aborted, then AbortOperation must be called - simply aborting the XMLHttpRequest invocation won't do help as the operation will continue until completion.
Edit
From this question: ASP.Net: How to stop page execution when browser disconnects?
You could also check the Response.IsClientConnected property to try and determine whether the invocation had been aborted.
Generally speaking, the server isn't going to know that a client has disconnected until it attempts to send data to it. See Best practice to detect a client disconnection in .NET? and Instantly detect client disconnection from server socket.
As nick_w wrote you can't stop the request being processed by the server once it has started. But there is ability to implement solution which will give you ability to cancel server task. Dino Esposito has several great articles about how such things can be implemented:
Canceling Server Tasks with ASP.NET AJAX
And in the following articles to implement pooling to server Dino Esposito describes how to use SignalR library:
Build a Progress Bar with SignalR;
Long Polling and SignalR
So if you really need to cancel some task on server these articles can be used as starting point to implement required solution.
Related
I have a web service that receives requests from users and returns some json. I need to save the json string in the database so for the moment, the write query occurs before the response is sent back.
Is there a way to send the response first and then do the write query, after the response left the web service?
Thanks.
There's a couple of different options here - they all have tradeoffs, though, and would be pretty esoteric. You don't mention why you want to do this, so I'm guessing performance. If that's the case, I think you're barking up the wrong tree - a simple write is almost certainly not your performance problem.
So, off the top of my head:
Queuing, as Ragesh mentions, would be a nice approach. This gets you similar semantics of a transaction, while off loading the write. You still have to write to the queue, though, which may be about the same overhead as writing to the DB.
You could spawn a new thread (using either the ThreadPool or System.Threading.Thread - there's some debates about which is preferable in ASP.NET) to handle the write. This can generally work, but you may have issues with unhandled exceptions, app domain restarts, etc.
You could store the JSON data into a static or Application variable, then use a Timer to periodically write them to the DB. This will be multithreaded code, so you will need to synchronize read/writes to the collection.
Similar to #3, store the JSON data into Cache and use the invalidation callback to write to the DB.
Lots of variations on store somewhere (memory, disk, flat DB table, etc.), process later (ASP.NET, scheduled task, Windows Service, Sql Agent, etc.).
#frenchie says: a response starts by reading the json string from the db and ends with writing it back. In other words, if the user sends a request, the json string that's going to be read must be the one that was written in the previous response.
That complicates things, since inherent in async work is not knowing when something is done. If you require the async portion (writing back to the DB) to be done before handling the next request, you'll have to execute a wait to make sure it actually completed. In order to do that, you'll need to keep server side state on the client - not exactly a best practice as far as services go (though, it sounds like you're already doing that with these JSON request/response pairs).
Given the complications, I would make sure that you've done your profiling and determined it is indeed a performance problem.
You can do schedule a query work like
ThreadPool.QueueUserWorkItem(state =>
this.AsynchronousExecuteReference());
// and run
static void AsynchronousExecuteReference()
{
// run here your sql update
}
One other example using Thread inside an class and you can pass parameters to it.
public class RunThreadProcess
{
// Some parametres
public int cProductID;
// my thread
private Thread t = null;
// start it
public Thread Start()
{
t = new Thread(new ThreadStart(this.work));
t.IsBackground = true;
t.SetApartmentState(ApartmentState.MTA);
t.Start();
return t;
}
// actually work
private void work()
{
// do thread work
all parametres are available here
}
}
And here is how I run it
var OneAction = new RunThreadProcess();
OneAction.cProductID = 100;
OneAction.Start();
Do not worry about memory, CG knows that this process is used until the thread ends, so I have check it and CG not delete it and wait the thread to ends.
You should look at using message queues like MSMQ, ActiveMQ or RabbitMQ to do this. When you receive your request, you'll put the relevant data in to the queue, and send your response to the client. At the other end of the queue, you'll have some process that reads from the queue and inserts data in to your database.
this is missing the point of a request/response. unless you want to get into async commands like a service bus, but that's pub/sub, not request/response. the point of request/response is to do the work on the server after receiving the request and before sending the response. even if the work is sending an async message to a service bus.
You could try moving your web service URL to an ASPX page where the lifecycles come in to play.
In the code-behind, call your routine that does the main portion of the work in Page_Load or Page_Prerender (or whenever is appropriate prior to the response being sent) and then do your DB work in the Page_Unload event which occurs after the response has been sent (http://msdn.microsoft.com/en-us/library/ie/ms178472.aspx).
I am loading a gridview using a code based on this:
http://msdn.microsoft.com/en-us/library/ms366515%28v=VS.80%29.aspx
I am using callbacks to populate the grid, sometimes there is a lot of data or the user wants to cancel.
How can I cancel the callback from being processed on the server when user hit cancel??
thanks
Searched quite extensively and found that it is possible to Cancel Server Tasks with ASP.NET & AJAX
Although I'm not good with AJAX, Found some links that will help you,
Here's how to Canceling Server Tasks with ASP.NET & AJAX and here's a forum thread on something similar to your problem.
Hope it helped !
AFAIK, you cannot cancel the server side call back processing once initiated. At the most, you can have some client (browser) side logic that will ignore callback results.
Regardless, I will suggest you to use ASP.NET AJAX (UpdatePanel or Script Services) rather than using ICallbackEventHandler. It's quite simple to use and more flexible. Besides, you also have options such as cancelling callbacks : see this article for cancelling update panel callback (note that cancel really means stop waiting for (& ignoring) callback results, the server side processing would happen).
Once you've initiated a request to the server, the client cannot cancel it. Ignoring the mechanics around any possible "cancellable method", you've started a request with the server. Any further communication will result in a new request, so that original request will continue until it has finished. Remember HTTP is a stateless protocol, each request has no knowledge of any previous request, and because of that, how could it cancel a previous request?
You're best bet would be to just ignore the server response, or if you actually need to cancel a long running task that may still be processing on the server, you need to bake in that support yourself, as the web server will not natively support it. To do that, you'll likely need some way of persisting the task state across multiple http requests, and have the original request (the one running that task) be monitoring some sort of cancellation flag.
Just remember though, in the above scenario, you wouldn't be cancelling the request, but the task the request is running.
We have a web front end on our business layer server.
Certain pages in our web application instantiate very long running tasks (could be up to 10+ minutes). The way that these requests are handled is like so: -
(on the HTTP request thread)
we make a connection to the business server.
we create a new thread to make the long running call passing in the connection object.
The HTTP request then completes, passing a handle back to the browser,
the browser periodically polls the web server to get updates on the long running task progress.
All requests to the business server are authenticated - the connection's user principal page must have permission to call the method on the business server.
This mechanism works fine as long as our web application is running in Classic mode.
When we run in pipeline mode, we get ObjectDisposedExceptions when the browser polls.
System.ObjectDisposedException: Safe handle has been closed
at System.StubHelpers.StubHelpers.SafeHandleC2NHelper(Object pThis, IntPtr CleanupWorkList)
at Microsoft.Win32.Win32Native.GetTokenInformation(SafeTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, ref UInt32 ReturnLength)
at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, ref UInt32 dwLength)
at System.Security.Principal.WindowsIdentity.get_User()
at System.Security.Principal.WindowsIdentity.GetName()
at System.Security.Principal.WindowsIdentity.get_Name()
the problem appears to be that the windows principal used to make the connection is disposed when the original request ends (which is understandable - in fact I am surprised that the code worked at all!).
As a way around this problem I was wondering if it was possible to either create a duplicate of the HTTP request principal and use that to create the connection (and dispose of it when the long running task completes) or would it be possible to impersonate the HTTP request principle on the worker thread even after the principal is disposed?
Update
(My comment under Aliostad's question was incorrect: the test page did fail. I managed to confuse myself sufficiently that I wrote my test page so that it did not exercise the same code path as the real (faulting) code. Nevermind!)
I have written a "workaround" for this problem: -
I am in the fortunate position of knowing what roles/groups the business server logic will be querying for before the call to the business server is made. So my workaround is to create a new generic principal based upon the request's principal's membership of these roles. The long running task is run using the generic principal.
I am not 100% happy with this workaround because it is very much a "hack" - i.e. I can see that it would easily fall down if some logic did the (eminently sensible) check of verifying that the principal's identity is authenticated.
So I would still very much appreciate any help / insight into this issue.
Thanks
OK, here is my catch on this.
First of all, if you create a thread, all the current thread's security context will be copied to the new thread - by default. This operation is heavy but much needed (as you can imagine most things will not work without it). In case you need to prevent it and you do not need the copying of context, there is a way to do it and it has been explained in Richter's C# via CLR. Lucky enough, he has shared this very bit of the book here and basically calling a static method to prevent context to be flowed:
ExecutionContext.SuppressFlow();
I cannot think this is being called in WCF although using Reflector, I found a single use of it in here:
[SecuritySafeCritical]
private IAsyncResult BeginGetContext(bool startListening)
{
Exception exception;
do
{
exception = null;
try
{
try
{
if (ExecutionContext.IsFlowSuppressed())
{
return this.listener.BeginGetContext(this.onGetContext, null);
}
using (ExecutionContext.SuppressFlow())
{
return this.listener.BeginGetContext(this.onGetContext, null);
}
}
// .... the rest
Interestingly enough, this is used in 3 places one of them in SharedHttpTransportManager.
Now all this might look like we have found the issue and it is a bug but I very much doubt it.
My hunch is that there is a process recycling happening in between and the context is lost. The way to prove or disprove this would be to use perfmon to register all process recycles and find out if any was in between.
My solution is basically - which you might not like! - to simply insert an item into a queue (MSMQ or a simple database queue) and have a windows service reading it. With this operation being so important, I would never trust IIS to carry out to the finish.
Hope this is useful to you.
I'm new to web development so I'm not sure what's the best option for the problem that I'm having.
Basically I have a web application that calls a web service for processing some data.
This process may take a long time (hours) and I would to know if there is an easy way to send some status information to the client from time to time.
Right now, the client makes the request from the browser and it just waits there until it finishes.
How can I send some information from the web service? I would like to send a percentage and some additional text specifying what is being done.
Thanks
WCF services can be marked as [OneWay] so that they don't return a response.
or, you could have the service kick off the process in an async manner and then just return to the client that the process has/or hasn't kicked off.
Then, the client can poll another method as the other user has suggested.
If you process takes hours you definitely can't use a sync service because you'll hit your execution timeout or rather the connection timeout for the client.
Maybe you can poll another method for status?
If I were you, I would make the original request asynchronous, as in instead of waiting for the response, it just "starts" the task and returns immediately. Then I would have a separate method on your web service that the app can poll periodically to get the status of the job. once it completes, it can display the data like the original request was doing.
if you want to do it synchronously, you can turn off Response.Buffer and write directly to the response.
The problem is as follows:
An external server sends incoming SMS messages converted to HTTP requests into my sometimes very time-consuming .aspx page. If no response is returned to the external server in 20 seconds, this is considered as an timeout and the same message is sent to my aspx page again (and maybe again....)
The optimal solution for me would be that the aspx page reads the incoming message (as an HTTP request to the aspx page), starts the processing of the message in another thread, and immediately renders response back to the external server. The external server has no interest in other stuff than the HTTP status (normally 200). When the processing of the message is completed this results in an entry into the log file of the application.
The processing of the message is done by making another web request to an aspx page, and I have tried to use the BeginGetResponse method for the web request, and have created a handler for handling of the completed web request to the processing page. The problem is that the handler seems to not be called, most likely because the aspx page's lifecycle is ended before the asynchrounous web request is completed.
Has anyone any good solution for this problem? I have also looked at the async page model, but this also seems to not be a solution for me because the response should be returned to the external server before the processing of the message is completed.
Regards, Eivind
I'd be very wary of using threads in ASP.Net in this manner. Using them to take advantage of multiple cores is one thing. Using them to set up some kind of concurrent response technique seems like a recipe for disaster. Especially when there is a far more elegant solution.
Your ASP.Net application should merely take the message and toss it in a database and send the success reply. It's job is done. The job of delivering the message should be handled by some kind of service or daemon. Windows Services are kind of a pain to build and maintain so perhaps just a scheduled task that runs every 30 seconds or so checking for queued messages in the DB would suit your purposes just fine.
I've seen a lot of people try to use threads in ASP.Net when they really should just be creating a background service. The results are never as reliable as you would hope.
Async page model is definitely not the solution. Have you tried using the unload event to do EndRequest? I really don't know if that would work but it is worth a try. The most robust way is to use Windows Service to run the async request.