Releasing a connection in .NET HTTPHandler - c#

I am currently implementing an HTTP Handler that will take a POST of some XML data from some 3rd party, then will do some work with it. The processing that I will be doing with the XML has potential to take some time. Once I yank out the XML from the POST, there is no need to keep the connection open with the client while I process the data. As I don't have any control of when the client will time out posting to me, I just want to grab the XML and let the connection go.
Is there any easy way to go about this? Using the Response.Close() isn't correct, as it doesn't close the connection properly. Response.End() exits my HTTP Handler all together. I could throw the processing into a background thread, but I heard that can be a little risky in ASP.NET as the AppDomain can be torn down which could kill my process in the middle.
Any thoughts would be much appreciated. Thanks for the help!

Save received data to some sort of permanent queue (MSMQ for example).
Exit handler.
Process data from queue in another application, for example in windows service.
This is not exactly "easy way", but safe and fast for customers.

Thanks everyone for your input. The way I went about this, so others can ponder it as a solution:
The queuing would probably be the most "correct" means, but it would take some extra implementation that really is just over the top for what I am intending to do. Using the information from http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx
First I create my processing class and spin that up in a background thread to do the work after I get the XML from the client. This releases the connection while my worker thread continues in the background.
I registered my processing class as an IRegisteredObject. I the implemented the Stop(bool immediate) method
public void Stop(bool immediate)
{
if (!immediate && _working)
return;//don't unregister yet, give it some time
if(immediate && _working)
{
//TODO: Log this instance
}
HostingEnvironment.UnregisterObject(this);
}
I set my _working variable to true when I am processing work, and unset it when done. If in the rare case I am processing work and stop gets called because the AppDomain is getting taken down, it will first just return without unregistering itself. This gives my process a bit more time to finish up. If when the method gets called the second time with the immediate flag set to true, it quickly logs the issue and then unregister itself.
This may not be the ultimate solution, but for my purposes, this will take care of alerting me when the very rare condition happens, as well as not holding up the client's connection as I process the data.

If you're using .NET 4.5, check out HttpTaskAsyncHandler.
From the linked page:
Asynchronous HTTP handlers The traditional approach to writing asynchronous handlers in ASP.NET is to implement the IHttpAsyncHandler
interface. ASP.NET 4.5 introduces the HttpTaskAsyncHandler
asynchronous base type that you can derive from, which makes it much
easier to write asynchronous handlers. The HttpTaskAsyncHandler type
is abstract and requires you to override the ProcessRequestAsync
method. Internally ASP.NET takes care of integrating the return
signature (a Task object) of ProcessRequestAsync with the older
asynchronous programming model used by the ASP.NET pipeline. The
following example shows how you can use Task and await as part of the
implementation of an asynchronous HTTP handler:
public class MyAsyncHandler : HttpTaskAsyncHandler
{
// ...
// ASP.NET automatically takes care of integrating the Task based override
// with the ASP.NET pipeline.
public override async Task ProcessRequestAsync(HttpContext context)
{
WebClient wc = new WebClient();
var result = await
wc.DownloadStringTaskAsync("http://www.microsoft.com");
// Do something with the result
}
}

Related

Long blocking while loop in ASP.NET MVC Web API application

I've been given a Perl script implementation of a task by a third party product vendor. My job is to translate it into my ASP.NET MVC5 web application.
One component of the perl script is a while loop with this in it:
### Only run this task every second, that's plenty
sleep 1;
Basically they're doing stuff in a while loop at 1 second intervals (pseudo code):
While (condition)
{
-go get an m3u8 playlist file from the web
-parse it line by line
-look for a particular thing in it
-If you find it, break out of this loop and do stuff with it
}
It typically takes between 20-30 tries (20-30 seconds) to find the thing.
Is this the kind of thing asynchronous programming with async and await is geared toward or is this something one just shouldn't have in a web app?
The process would be exposed via ajax call to Web API. If it is feasible, could someone provide some pseudo code on how it might work without blocking the app?
If it is feasible, could someone provide some pseudo code on how it might work without blocking the app?
AJAX calls are always nonblocking. There's nothing special you need to do on the server side for this.
I would recommend using async/await, just so that you don't use up an ASP.NET thread sleeping:
public async Task<MyResult> GetThing()
{
While (condition)
{
-go get an m3u8 playlist file from the web
-parse it line by line
-look for a particular thing in it
-If you find it, break out of this loop and do stuff with it
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
But note that the async is only used to free up a thread on the ASP.NET server side. It has no effect on the client whatsoever. The client makes the AJAX call, and asynchronously handles completion, regardless of the server's implementation.
you can use async/await, but thats more about synchroizing async behaviour. Your problem is a little different, you have a long running process which you can't block on, so you need a way to trigger it to start, providing updates, and then handling completion. You could use something like signalR for this
If you want to use ajax for this, then something like for your API...
StartJob() -> return GUID
JobStatus(guid) -> either, InProgress ( % complete if you can), Final Result, or Error
then client side, Start it, then poll for status until complete.
Implementation wise, you just Start a task and store it in a cache associated with a GUID.
If you want to get fancy pants, you could use something like Microsoft Orleans or Akka to do the processing.

Async call of ASMX web service

In my scenario when ever user changes some fields in the program and does a SAVE, a webserivce request is sent to save some logging information into the database. I did some search on the website and found this solution for Async calls:
ThreadPool.QueueUserWorkItem(delegate
{
// Create an instance of my webservice object.
// call its Log webmethod.
});
But since I don't have much experience with webservices and Async calls so I wanted to show you the scenario I have and the way I am handling it to get your opinion about it and if it the right way to do this. Thanks for suggestions.
Can you tolerate the logging work to be lost? Only then should you start "background work" in an ASP.NET app.
QueueUserWorkItem will work. The more modern version is Task.Run. Make sure you catch errors that happen on that thread-pool thread. If not, you'll never find out about bugs and silently lose work.
If you expect a high volume of such calls, or expect them to take a long time, consider using async IO. It does not use any thread while in progress (not even a background thread).

Is it advisable to create thread for each client request?

Code:
class Controller
{
Some Action Method()
{
...
...
new Thread(() =>
{
//WCF cal- wil execute for around 10 secs.
var result = service.SubmitAndCreateApp(params);
sessionModel.IsAppCreated = result;
}).Start();
return jsonresult;
}
}
Since my WCF call is taking too much time, I don't want to use thread pool and make it starve.
It is evident here that the thread is being created for each client request. How can I optimize this or any other alternative way to achieve this in .Net 4.0 (VS 2010)?
To put it simply: no, don't do this.
That said, you can look at the Task Parallel Library (TPL) in ASP.Net, which can achieve exactly what you are trying to do.
Quick search yielded this posting, which I only glanced over but seems on-point:
http://vizagtechie.blogspot.com/2013/03/parallel-programming-in-aspnet-mvc.html
No. Your server will get DDOS'ed completely. At the very least, request a thread from the thread pool rather than creating your own by hand. If the thread pool runs out, you'll be waiting for one to become available. The rest of the server will continue to be able to work. Of course, your mileage may vary based on many factors.
Each request already gets a thread, so by adding another thread manually, you're creating two threads per request, effectively having your server's ability to field requests. Now, I won't be as apocalyptic as others: on a beefy enough server not fielding thousands of requests per second or more, you'll probably still be okay. It's still bad design, though.
You didn't mention what version of C# you're using on but on 5.0+, you now have async which is how you'd typically handle this situation:
public async Task<ActionResult> SomeActionWithLongRunningProcess()
{
await LongRunningProcess();
return View();
}
This will cause .NET to offload the request, freeing up the thread, until LongRunningProcess() completes.
Your code can complete the call to Some Action Method() and return jsonresult prior to the completion of your WCF call to service.SubmitAndCreateApp(params) (for practical purposes, assume this will happen 100% of the time). If you want that to happen, then your code is fine. If you need the response from the service call in sessionModel.IsAppCreated for your JSON result, however, your code is very broken.
To fix this, you would need to block the action method's thread until the thread it created terminates. This fact along with the fact that the underlying WCF communication channel will already create its own thread to await response from the WCF service call (a synchronous WCF call is really just an async call that blocks until the response is received) makes creating a new thread pointless.

Is it possible to return an ASP page before continuing slow server side work (eg logging)

Is it possible to return the page response to the user, before you've finished all your server side work?
Ie, I've got a cheap hosting account with No database, but I'd like to log a certain event, by calling a webservice on my other, more expensive hosting account (ie, a very slow logging operation)
I don't really want the user to have to wait for this slow logging operation to complete before their page is rendered.
Would I need to spin up a new thread, or make an asynchronous call? Or is it possible to return the page, and then continue working happily in the same thread/code?
Using ASP.Net (webforms) C# .Net 2.0 etc.
You would probably need a second thread. An easy option would be to use the ThreadPool, but in a more sophisticated setup a producer/consumer queue would work well.
At the simplest level:
ThreadPool.QueueUserWorkItem(delegate {
DoLogging(state details);
});
You sure can - try Response.Flush.
That being said - creating an asynchronous call may be the best way to do what you want to do. Response.Flush simply flushed the output buffer to the client, an asynchronous call would allow you to fire off a logging call and not have it impact the client's load time.
Keep in mind that an asynchronous call made during the page's life cycle in ASP.NET may not return in time for you to do anything with the response.

A reasonable use of threading in C#?

As part of a large automation process, we are calling a third-party API that does some work calling services on another machine. We discovered recently that every so often when the other machine is unavailable, the API call will spin away sometimes up to 40 minutes while attempting to connect to the remote server.
The API we're using doesn't offer a way to specify a timeout and we don't want our program waiting around for that long, so I thought threads would be a nice way to enforce the timeout. The resulting code looks something like:
Thread _thread = new Thread(_caller.CallServices());
_thread.Start();
_thread.Join(timeout);
if (_thread.IsAlive)
{
_thread.Abort();
throw new Exception("Timed-out attempting to connect.");
}
Basically, I want to let APICall() run, but if it is still going after timeout has elapsed, assume it is going to fail, kill it and move on.
Since I'm new to threading in C# and on the .net runtime I thought I'd ask two related questions:
Is there a better/more appropriate mechanism in the .net libraries for what I'm trying to do, and have I committed any threading gotchas in that bit of code?
Thread.Abort() is a request for the thread to abort, and gives no guarantee that it will do so in a timely manner. It is also considered bad practice (it will throw a thread abort exception in the aborted thread, but it seems like the 3rd party API offers you no other choices.
If you know (programmatically) the address of the remote service host you should ping it before you transfer control to the 3rd party API.
If not using a backgroundworker, you could set the thread's IsBackgroundThread to true, so it doesn't keep your program from terminating.
Bad idea. Thread.Abort doesn't necessarily clean up the mess left by such an interrupted API call.
If the call is expensive, consider writing a separate .exe that makes the call, and pass the arguments to/from it using the command line or temporary files. You can kill an .exe much more safely than killing a thread.
You can also just use a delegate... Create a delegate for the method that does the work, Then call BeginInvoke on the delegate, passing it the arguments, and a callback function to handle the return values (if you want)...
Immediately after the BeginInvoke you can wait a designated time for the asynch delegate to finish, and if it does not in that specified time, move on...
public delegate [ReturnType] CallerServiceDelegate
([parameter list for_caller.CallService]);
CallerServiceDelegate callSvcDel = _caller.CallService;
DateTime cutoffDate = DateTime.Now.AddSeconds(timeoutSeconds);
IAsyncResult aR = callSvcDel.BeginInvoke([here put parameters],
AsynchCallback, null);
while (!aR.IsCompleted && DateTime.Now < cutoffDate)
Thread.Sleep(500);
if (aR.IsCompleted)
{
ReturnType returnValue = callSvcDel.EndInvoke(aR);
// whatever else you need to do to handle success
}
else
{
callSvcDel.EndInvoke(aR);
// whatever you need to do to handle timeout
}
NOTE: as written AsynchCallback could be null, as the code retrieves the return value from the EndInvoke(), but if you want to you can have the CallService() method call the AsynchCallback delegate and pass it the return values instaed...
It might work, but nobody could say for sure without an understanding of the third-party API. Aborting the thread like that could leave the component in some invalid state that it might not be able to recover from, or maybe it won't free resources that it allocated (think - what if one of your routines just stopped executing half-way through. Could you make any guarantees about the state your program would be in?).
As Cicil suggested, it might be a good idea to ping the server first.
Does your application run for long periods of time or is it more of a run-as-needed application? If it's the latter, I personally would consider using the Thread.Abort() option. While it may not be the most desirable from a purist's perspective (resource management, etc.), it is certainly straightforward to implement and may foot the bill given the way your particular application works.
The idea of a separate executable makes sense. Perhaps another option would be to use AppDomains. I'm not an expert in this area (I welcome refinements/corrections to this), but as I understand it, you'd put the API call in a separate DLL and load it into a separate AppDomain. When the API call is finished or you have to abort it, you can unload the AppDomain along with the DLL. This may have the added benefit of cleaning up resources that a straightforward Thread.Abort() will not.

Categories

Resources