Async webmethod without timeout - c#

I need a console app which will calling webmethod.
It must be asynchronous and without timeout (we don't know how much time takes this method to deal with task.
Is it good way:
[WebMethod]
[SoapDocumentMethod(OneWay = true)]
??

Don't use one-way if you need results
First, if you need a response from your method, you don't want [SoapDocumentMethod(OneWay = true)]. This attribute creates a "fire and forget" call which never returns a response back to the caler and must return void. Instead, use a regular method call and call it async.
One method or two?
If you're using ASMX, there are two basic solutions: one method with a very long timeout, or two methods (as #Aaronaught suggested above): one to kick off the operation and return an ID of the operation, and another to pass in the ID and retrieve results (if available).
Personally, I would not recommend this two-method approach in most cases because of the additional complexity involved, including:
client and server code needs to be changed to suppport 2-step invocation
ASP.NET intrinsic objects like Request and Response are not available when called from a background task launched with ThreadPool.QueueUserWorkItem.
throttling on a busy server gets much harder if there are multiple threads involved with each request.
the server must hang onto the results until the client picks them up (or you decide to throw them out), which may eat up RAM if results are large.
you can't stream large, intermediate results back to the client
True, in some scenarios the 2-method approach may scale better and will be more resilient to broken network connections between client and server. If you need to pick up results hours later, this is something to consider. But your operations only take a few minutes and you can guarantee the client will stay connected, given the addiitonal dev complexity of the 2-method approach I'd consider it a last resort to be used only if the one-method solution doesn't match your needs.
Anyway, the solution requires two pieces. First, you need to call the method asynchronously from the client. Second, you need to lengthen timeouts on both client and server. I cover both below.
Calling ASMX Web Services Asynchronously
For calling an ASMX web service asynchronously from a command-line app, take a look at this article starting with page 2. It shows how to call a web service asynchronously from a .NET cilent app using the newer Event-Based Async Pattern. Note that the older .NET 1.0 approach described here, which relies on BeginXXX/EndXXX methods on the proxy, is not recommended anymore anymore since Visual Studio's proxy generator doesn't create those methods. Better to use the event-based pattern as linked above.
Here's an excerpt/adaptation from the article above, so you can get an idea of the code involved:
void KickOffAsyncWebServiceCall(object sender, EventArgs e)
{
HelloService service = new HelloService();
//Hookup async event handler
service.HelloWorldCompleted += new
HelloWorldCompletedEventHandler(this.HelloWorldCompleted);
service.HelloWorldAsync();
}
void HelloWorldCompleted(object sender,
HelloWorldCompletedEventArgs args)
{
//Display the return value
Console.WriteLine (args.Result);
}
Lengthen server and client timeouts
To prevent timeouts, http://www.dotnetmonster.com/Uwe/Forum.aspx/asp-net-web-services/5202/Web-Method-TimeOut has a good summary of how to adjust both client and server timeouts. You didn't specify in your question if you own the server-side method or just the client-side call, so the excerpt below covers both cases:
there has two setttings that will
affect the webservice call timeout
behavior:
** The ASP.NET webservice's server-side httpruntime timeout
setting, this is configured through
the following element:
httpRuntime Element (ASP.NET Settings Schema)
http://msdn2.microsoft.com/en-us/library/e1f13641.aspx
<configuration> <system.web>
<httpRuntime .............
executionTimeout="45"
.............../> </system.web>
</configuration>
Also, make sure that you've set the
<compilation debug="false" /> so as to
make the timeout work correctly.
** If you're using the wsdl.exe or VS IDE "add webreference" generated
proxy to call webservice methods,
there is also a timeout setting on the
client proxy class(derived from
SoapHttpClientProtocol class). This is
the "Timeout" property derived from
"WebClientProtocol" class:
WebClientProtocol.Timeout Property http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.webclientprotocol.timeout.aspx
Therefore, you can consider adjusting
these two values according to your
application's scenario. Here is a
former thread also mentioned this:
http://groups.google.com/group/microsoft.public.dotnet.framework.webservices/browse_thread/thread/73548848d0544bc9/bbf6737586ca3901
Note that I'd strongly recommend making your timeouts long enough to encompass your longest operation (plus enough buffer to be safe should things get slower) but I wouldn't recommend turning off timeouts altogether. It's generally bad programming practice to allow unlimited timeouts since an errant client or server can permanently disable the other. Instead, just make timeouts very long--- and make sure to be logging instances where your clients or servers time out, so you can detect and diagnose the problem when it happens!
Finally, to echo the commenters above: for new code it's best to use WCF. But if you're stuck using ASMX web services, the above solution should work.

If the method is actually one-way, and you don't care about the result or ever need to follow up on the status of your request, then that is good enough.
If you do need a result (eventually), or need to check on the status of the operation, then this won't work very well. What your method should do in that case is start the work in a background thread, then immediately return an ID that can be used in a different web method to look up the status.
So something like this:
public enum JobStatus { Running, Completed, Failed };
public class MyService : WebService
{
[WebMethod]
public int BeginJob()
{
int id = GetJobID();
// Save to a database or persistent data source
SaveJobStatus(id, JobStatus.Running);
ThreadPool.QueueUserWorkItem(s =>
{
// Do the work here
SaveJobStatus(id, JobStatus.Completed);
}
return id;
}
[WebMethod]
public JobStatus GetJobStatus(int id)
{
// Load the status from database or other persistent data source
return ( ... )
}
}
That's one method to start the work, and another method to check on its status. It's up to the client to poll periodically. It's not a very good system, but you don't have a lot of options with ASMX.
Of course, if you do need a response from this operation, a much better way is to use WCF instead. WCF gives you callback contracts, which you can use to begin a one-way operation and subscribe to a notification when that operation is complete, which eliminates the need for polling above.
So, to summarize all that:
If you don't need any response or status updates, just use IsOneWay = true.
If you do need updates, and can use WCF on the service side, use that with a callback contract. You should be using WCF for new Web Service projects anyway.
If you need updates and cannot use WCF, do the work in a background thread and implement a periodic polling system with an additional status-check web method.

Related

Async Task.Run in a self hosted web service - is it "wrong usage" as long as it works?

I am working on a project with the following details:
No IIS or other 3rd party webservers involved
.NET 4.5 Windows application, which acts as a "server"
The server starts multiple WCF webservices, all of them self-hosted
The webservices are accessible to multiple users
Here is a most simple example of one of the many webservice methods:
public async Task<int> Count()
{
int result = 0;
//There is nothing to await here, so I use Task.Run
await Task.Run(() =>
{
using (IDB ctx = new DB())
{
result = ctx.Customers.All.Count();
}
//Here could happen a lot more
//System.Threading.Thread.Sleep(10000);
}).ConfigureAwait(false);
return result;
}
As you can see, I am using Task.Run to access some data, because non of the repository interfaces offers async methods. I can not await anything. If I wanted to do "real async", I would have to rewrite the complete repository interface.
If I would not use Task.Run, the server would be blocking all other incoming requests.
My 2 questions are:
Is there anything wrong using Task.Run in this scenario?
Even if it is working and maybe not completely wrong, is there a better, more professional solution to call synchronous code in an async method?
The initial reason for this question is, that I read, that using Task.Run in an async method is "fake async". (I think Task.Run starts a new thread, while "real async" code does not)
I answered my own question, see answer below. I hope it can help others.
Yes it is fake async and less scalable as it starts a thread and blocks it, there is no giving it back until its finished.
However,
as Stephen Clearly alludes to in his Task.Run Etiquette and Proper Usage
I call such methods “fake-asynchronous methods” because they look
asynchronous but are really just faking it by doing synchronous work
on a background thread. In general, do not use Task.Run in the
implementation of the method; instead, use Task.Run to call the
method. There are two reasons for this guideline:
Consumers of your code assume that if a method has an asynchronous signature, then it will act truly asynchronously. Faking
asynchronicity by just doing synchronous work on a background thread
is surprising behavior.
If your code is ever used on ASP.NET, a fake-asynchronous method leads developers down the wrong path. The goal of async on the server
side is scalability, and fake-asynchronous methods are less scalable
than just using synchronous methods.
Also Stephen Toub (aka Mr. Parallel) Should I expose asynchronous wrappers for synchronous methods?
The idea of exposing “async over sync” wrappers is also a very
slippery slope, which taken to the extreme could result in every
single method being exposed in both synchronous and asynchronous
forms. Many of the folks that ask me about this practice are
considering exposing async wrappers for long-running CPU-bound
operations. The intention is a good one: help with responsiveness.
But as called out, responsiveness can easily be achieved by the
consumer of the API, and the consumer can actually do so at the right
level of chunkiness, rather than for each chatty individual operation.
Further, defining what operations could be long-running is
surprisingly difficult. The time complexity of many methods often
varies significantly.
However, you actually really dont fit into either of these categories. From your description you are hosting this WCF service. It will run your code asynchronously anyway if you have set the InstanceContextMode and ConcurrencyMode correctly. Your will additionally have the ability to run the TBA wrappers for your call form the client, assuming you generated your proxies with the appropriate settings.
If i understand you correctly, you could just let this method be entirely synchronous, and let WCF take care of the details and save resources
Update
An example: If I use Task.Run inside any webservice methode, I can
even call Thread.Sleep(10000) inside Task.Run and the server stays
responsive to any incoming traffic.
I think the following might help you the most
Sessions, Instancing, and Concurrency
A session is a correlation of all messages sent between two endpoints.
Instancing refers to controlling the lifetime of user-defined service
objects and their related InstanceContext objects. Concurrency is the
term given to the control of the number of threads executing in an
InstanceContext at the same time.
Its seems like your WCF service is setup for InstanceContextMode.PerSession, and ConcurrencyMode.Single. If your service is stateless you probably want to use InstanceContextMode.PerCall and only use async when you have something that truly can be awaited
First of all: Thank all of you for your hints. I needed them to dive deeper into the problem.
I have found the real solution to this problem and I think, I could add some value to the community by answering my own question in detail.
The solution can also be found in this great article: https://www.oreilly.com/library/view/learning-wcf/9780596101626/ch04s04.html
Here is a quick summary of the initial problem and the solution:
The goal
My goal is to host multiple self-hosted WCF services in a .NET 4.5 application
All self-hosted WCF services are accessible to multiple clients
All self-hosted WCF services MUST NOT block each other when multiple users are using them
The problem (and the false solution) (my initial question)
My problem was, that whenever one client used a webservice, it would block the other webservices until it returned to the client
It did not matter what kind of InstanceContextMode or ConcurrencyMode I used
My false solution was to use async and Task.Run ("Fake Async"). It worked, but it was not the real solution.
The solution (found in the article)
When self-hosting WCF webservices, you MUST make sure, that you always call ServiceHost.Open in a seperate thread, different from the UI thread
Whenever you open a ServiceHost in a Console, WinForms or WPF application, or a Windows Service, you have to be aware, at which time you call ServiceHost.Open and how you use the ServiceBehaviorAttribute.UseSynchronizationContext
The default value for ServiceBehaviorAttribute.UseSynchronizationContext is True. (this is bad and leads to blocking!)
If you just call ServiceHost.Open, without setting UseSynchronizationContext = false , all ServiceHosts will run in the UI thread and block this thread and each other.
Solution 1 (tested and it works - no more blocking)
Set ServiceBehaviorAttribute.UseSynchronizationContext = false
Solution 2 (tested and it works - no more blocking)
Do NOT touch ServiceBehaviorAttribute.UseSynchronizationContext, just let it be true
But create at least one or multiple threads in which you call ServiceHost.Open
Code:
private List<ServiceHost> _ServiceHosts = new List<ServiceHost>();
private List<Thread> _Threads = new List<Thread>();
foreach (ServiceHost host in _ServiceHosts)
{
_Threads.Add(new Thread(() => { host.Open(); }));
_Threads[_Threads.Count - 1].IsBackground = true;
_Threads[_Threads.Count - 1].Start();
}
Solution 3 (not tested, but mentioned in the article)
Do NOT touch ServiceBehaviorAttribute.UseSynchronizationContext, just let it be true
But make sure, that you call ServiceHost.Open BEFORE the UI thread is created
Then the ServiceHosts will use a different thread and not block the UI thread
I hope this can help others with the same problem.

Wrapping a non async-method (which does web calls) into async

I know you should only use async for stuff which is not "CPU-intensive", e.g. file writes, web calls etc. and therefore I also know it doesn't makes sense to wrap every method into Task.Run or something similar.
However what should I do when I know a method does a web call, but it doesn't offer an async interface. Is it in this case worth to wrap it?
Concrete example:
I'm using CSOM (Client SharePoint Object Model) in my WebApi application (server) and want to get a SharePoint list.
This is normally done like this:
[HttpGet]
[Route("foo/{webUrl}")]
public int GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
context.ExecuteQuery();
return web.Lists.Count;
}
}
And I thought about changing it to something like this:
[HttpGet]
[Route("foo/{webUrl}")]
public async Task<int> GetNumberOfLists(string webUrl)
{
using (ClientContext context = new ClientContext(webUrl))
{
Web web = context.Web;
context.Load(web.Lists);
await Task.Run(() => clientContext.ExecuteQuery());
return web.Lists.Count;
}
}
Does it make sense and does it help? As I understand it, I just create / need a new thread for executing the query ("overhead") but at least the request thread will be free / ready for another request (that would be good).
But is it worth it and should it be done like this?
If so:
Isn't it strange that Microsoft doesn't offer the "async" method out of the box or did they just not care about it?
edit:
updated to use Task.Run as suggested in comment.
However what should I do when I know a method does a web call, but it doesn't offer an async interface.
Unfortunately still somewhat common. As different libraries update their APIs, they will eventually catch up.
Is it in this case worth to wrap it?
Yes, if you're dealing with a UI thread. Otherwise, no.
Concrete example... in my WebApi application (server)
Then, no, you don't want to wrap in Task.Run. As noted in my article on async ASP.NET:
You can kick off some background work by awaiting Task.Run, but there’s no point in doing so. In fact, that will actually hurt your scalability by interfering with the ASP.NET thread pool heuristics... As a general rule, don’t queue work to the thread pool on ASP.NET.
Wrapping with Task.Run on ASP.NET:
Interferes with the ASP.NET thread pool heuristics twice (by taking a thread now and then releasing it later).
Adds overhead (code has to switch threads).
Does not free up a thread (the total number of threads used for this request is almost equal to just calling the synchronous version).
As I understand it, I just create / need a new thread for executing the query ("overhead") but at least the request thread will be free / ready for another request (that would be good).
Yes, but all you're doing is jumping threads, for no benefit. The thread used to block on the query result is one less thread ASP.NET has to use to handle requests, so freeing up one thread by consuming another isn't a good tradeoff.
Isn't it strange that Microsoft doesn't offer the "async" method out of the box or did they just not care about it?
Some of the "older" MS APIs just haven't gotten around to adding async versions yet. They certainly should, but developer time is a finite resource.
This is my personal view of your problem and for me the above way is not required. When we host your API in IIS, the server assigns one thread from thread pool it has in the server. The IIS also has a setting of maxConcurrentRequestsPerCPU maxConcurrentThreadsPerCPU. You can setup these values to serve the request instead of handling the request all by yourself.

Correct way to implement a client-call to a long running server-side method

I am working on SOAP-client in WCF to communicate with a self-hosted WCF service for remote controlling a piece of software that I am developing. This software has a very long running operation (lets call it Print) that will run for several minutes, perhaps up to an hour. I am trying to figure out how to implement the method Print given the following requirements:
The server should be able to raise FaultExceptions to the client, in case something goes wrong.
The client should be informed ASAP should the connection to the service be lost.
The server-side process of Print should continue to run if disconnected, so that the client can reconnect and continue to monitor the process and abort it if necessary.
Since I am new to WCF, I am unsure how to implement this. I currently see two alternatives:
Make Print an async method so that I can "fire and forget" it until it finishes or throws a FaultException. This seems straight-forward, but I see this "problem": There is a client-side request timeout in WCF with default value of 1 minute, which also applies to async methods (if I am not mistaken) and which I would therefore have to increase significantly. This seems a bit like a hack.
Implement the async behavior of Print myself by splitting its behavior into a non-async method StartPringing that starts a server-side task for printing and returns directly (or throws an exception in case something goes wrong) and a client-callback method PrintingFinished. I could then use the callback PrintingFinished to signal to the client, when the print-process has finished or a use an additional callback PrintingFailed to send an exceptions in case something goes wrong. This implementation would be "hidden" behind the async method Print, so that it behaves like any other async method that might throw an exception. Here I see the following challenge: I will have to implement the whole exception callback-stuff myself, to handle exceptions that occur after StartPringing has returned (from StartPringing itself I can throw FaultExceptions).
For both cases I will have to work out how to detect, when the connection is servered (which I am currently doing using a ping method on the service) and then somehow get that event to throw an exception from within the method Print. Implementation-wise this seems more aligned with alternative (2), since I need to already implement all the other event handlers for when the print-process finishes or an exception is thrown. However I am unsure how I would implement this for alternative (1).
So which one of the two alternatives is "better". By better I mean the following considerations:
1. Aligned with the "standard" way in WCF for implementing such a long running method.
2. Maintainability and extensibility.
If I should consider any other alternative, I would be grateful for any other suggestion.
For what I understand of your problem I think if you need a real async communication with reliability to use a message queue like MSMQ. You can use it with WCF : https://msdn.microsoft.com/en-us/library/ms789048(v=vs.110).aspx
Update
In your case, you can use a SOAP call to send print command to the server because it sync and you need to know if the server handle the request. After in the printing operation is long and async. When this operation finish (exception or not) it need to notify client(s). But client could be shutdown for example. For that communication a Message Queue is the solution, MQ ensure that the message will be transmit.
https://en.wikipedia.org/wiki/Message_queue
If you don't want use MSMQ, you can implement a web service on client side to be notified by the printing server, using for example a UUID to match call and notification in a map in memory or in a Data Base.

Make Controller methods asynchronous or leave synchronous? [duplicate]

This question already has answers here:
When should I use Async Controllers in ASP.NET MVC?
(8 answers)
Closed 6 years ago.
I am working with a pre-existing C# ASP.NET MVC webapplication and I'm adding some functionality to it that I can't decide whether or not to make async.
Right now, the application home page just processes a page and a user logs in. Nothing more, and nothing asynchronous going on at all.
I am adding functionality that will, when the homepage is visited, generate a call to a Web API that subsequently calls a database that grabs an identifier and returns it to an HTML tag on the home page. This identifier will not be visible on the screen, only on the source/HTML view (this is being added for various internal tracking purposes).
The Web API/database call is simple, just grab an identifier and return it to the controller. Regardless, I'm wondering whether the app should make this call asynchronously? The website traffic isn't immense, but I'm still wondering about concurrency, performance and future scalability.
The one catch is that I'd have to make the entire ActionMethod async and I'm not sure what the affects of that would be. The basic pattern, currently synchronous, is below:
public ActionResult Index()
{
var result = GetID();
ViewBag.result = result.Data;
return View();
}
public JsonResult GetID()
{
var result = "";
var url = "http://APIURL/GetID";
using (WebClient client = new WebClient())
{
result = client.DownloadString(url);
}
return Json(result, JsonRequestBehavior.AllowGet);
}
Any thoughts?
First and foremost, realize the purpose of async, in the context of a web application. A web server has what's called a thread pool. Generally speaking, 1 thread == 1 request, so if you have a 1000 threads in the pool (typical), your website can roughly serve 1000 simultaneous requests. Also keep in mind that, it often takes many requests to render a single resource. The HTML document itself is one request, but each image, JS file, CSS file, etc. is also a request. Then, there's any AJAX requests the page may issue. In other words, it's not uncommon for a request for a single resource to generate 20+ requests to the web server.
Given that, when your server hits its max requests (all threads are being utilized), any further requests are queued and processed in order as threads are made available. What async does is buy you some additional head room. If there's threads that are in a wait-state (waiting for the results of a database query, the response from a web service, a file to be read from the filesystem, etc.), then async allows these threads to be returned to the pool, where they are then able to field some of those waiting requests. When whatever the thread was waiting on completes, a new thread is requested to finish servicing the request.
What is important to note here is that a new thread is requested to finish servicing the request. Once the thread has been released to the pool, you have to wait for a thread again, just like a brand new request. This means running async can sometimes take longer than running sync, depending on the availability of threads in the pool. Also, async caries with it a non-insignificant amount of overhead that also adds to the overall load time.
Async != faster. It can many times be slower, but it allows your web server to more efficiently utilize resources, which could mean the difference between falling down and gracefully bearing load. Because of this, there's no one universal answer to a question like "Should I just make everything async?" Async is a trade-off between raw performance and efficiency. In some situations it may not make sense to use async at all, while in others you might want to use it for everything that's applicable. What you need to do is first identity the stress points of your application. For example, if your database instance resides on the same server as your web server (not a good idea, BTW), using async on your database queries would be fairly pointless. The chief culprit of waiting is network latency, whereas filesystem access is typically relatively quick. On the other hand, if your database server is in a remote datacenter and has to not only travel the pipes between there and your web server but also do things like traverse firewalls, well, then your network latency is much more significant, and async is probably a very good idea.
Long and short, you need to evaluate your setup, your environment and the needs of your application. Then, and only then, can you make smart decisions about this. That said, even given the overhead of async, if there's network latency involved at all, it's a pretty safe bet async should be used. It's perfectly acceptable to err on the site of caution and just use async everywhere it's applicable, and many do just that. If you're looking to optimize for performance though (perhaps you're starting the next Facebook?), then you'd want to be much more judicious.
Here, the reason to use async IO is to not have many threads running at the same time. Threads consume OS resources and memory. The thread pool also cal be a little slow to adjust to sudden load. If your thread count in a web app is below 100 and load is not extremely spikey you have nothing to worry about.
Generally, the slower a web service and the more often it is called the more beneficial async IO can be. You will need on average (latency * frequency) threads running. So 100ms call time and 10 calls per second is about 1 thread on average.
Run the numbers and see if you need to change anything or not.
Any thoughts?
Yes, lot's of thoughts...but that alone doesn't count as an answer. ;)
There is no real good answer here since there isn't much context provided. But let's address what we know.
Since we are a web application, each request/response cycle has a direct impact on performance and can be a bottleneck.
Since we are internally invoking another API call from ours, we shouldn't assume that it is hosted on the same server - as such this should be treated just like all I/O bound operations.
With the two known factors above, we should make our calls async. Consider the following:
public async Task<ActionResult> Index()
{
var result = await GetIdAsync();
ViewBag.result = result.Data;
return View();
}
public async Task<JsonResult> GetIdAsync()
{
var result = "";
var url = "http://APIURL/GetID";
using (WebClient client = new WebClient())
{
// Note the API change here?
result = await client.DownloadStringAsync(url);
}
return Json(result, JsonRequestBehavior.AllowGet);
}
Now, we are correctly using async and await keywords with our Task<T> returning operations. This will help to ensure ideal performance. Notice the API change on the client.DownloadStringAsync too, this is very important.

Optimizing an ASMX web service with Multiple Long-Running Operations

I'm writing an ASP.NET web service using C# that has a DoLookup() function. For each call to the DoLookup() function I need my code to execute two separate queries: one to another web service at a remote site and one to a local database. Both queries have to complete before I can compile the results and return them as the response to the DoLookup method. The problem I'm dealing with is that I want to make this as efficient as possible, both in terms of response time and resource usage on the web server. We are expecting up to several thousand queries per hour. Here's a rough C#-like overview of what I have so far:
public class SomeService : System.Web.Services.WebService
{
public SomeResponse DoLookup()
{
// Do the lookup at the remote web service and get the response
WebResponse wr = RemoteProvider.DoRemoteLookup();
// Do the lookup at the local database and get the response
DBResponse dbr = DoDatabaseLookup();
SomeResponse resp = new SomeResponse( wr, dbr);
return resp;
}
}
The above code does everything sequentially and works great but now I want to make it more scalable. I know that I can call the DoRemoteLookup() function asynchronously ( RemoteProvider has BeginRemoteLookup / EndRemoteLookup methods) and that I can also do the database lookup asynchronously using the BeginExecuteNonQuery / EndExecuteNonQuery methods.
My question (finally) is this: how do I fire both the remote web service lookup AND the database lookup simultaneously on separate threads and ensure that they have both completed before returning the response?
The reason I want to execute both requests on separate threads is that they both potentially have long response times (1 or 2 seconds) and I'd like to free up the resources of the web server to handle other requests while it is waiting for responses. One additional note - I do have the remote web service lookup running asynchronously currently, I just didn't want to make the sample above too confusing. What I'm struggling with is getting both the remote service lookup AND the database lookup started at the same time and figuring out when they have BOTH completed.
Thanks for any suggestions.
You can use a pair of AutoResetEvents, one for each thread. At the end of thread execution, you call AutoResetEvents.Set() to trigger the event.
After spawning the threads, you use WaitAll() with the two AutoResetEvents. This will cause the thread to block until both events are set.
The caveat to this approach is that you must ensure the Set() is guarantee to be called, otherwise you will block forever. Additionally ensure that with threads you exercise proper exception handling, or you will inadvertently cause more performance issues when unhanded exceptions cause your web application to restart.
MSDN Has sample code regarding AutoResetEvent usage.
See Asynchronous XML Web Service Methods, How to: Create Asynchronous Web Service Methods and How to: Chain Asynchronous Calls with a Web Service Method.
But note the first paragraph of those articles:
This topic is specific to a legacy technology. XML Web services and XML Web service clients should now be created using Windows Communication Foundation (WCF).
BTW, doing things the way these articles say is important because it frees up the ASP.NET worker thread while the long-running task runs. Otherwise, you might be blocking the worker thread, preventing it from servicing further requests, and impacting scalability.
Assuming you can have a callback function for both the web request and the database lookup then something along these lines may work
bool webLookupDone = false;
bool databaseLookupDone = false;
private void FinishedDBLookupCallBack()
{
databaseLookupDone = true;
if(webLookupDone)
{
FinishMethod();
}
}
private void FinishedWebLookupCallBack()
{
webLookupDone = true;
if(databaseLookupDone)
{
FinishMethod();
}
}
I guess I don't have enough rep to upvote nor to comment. So this is a comment on John Saunders answer and Alan's comment on it.
You definitely want to go with John's answer if you are concerned about scalability and resource consumption.
There are two considerations here: Speeding up an individual request, and making your system handle many concurrent requests efficiently. The former both Alan's and John's answer achieve by performing the external calls in parallel.
The latter, and it sounds like that was your main concern, is achieved by not having threads blocked anywhere, i.e. John's answer.
Don't spawn your own threads. Threads are expensive, and there are already plenty of threads in the IO Threadpool that will handle your external calls for you if you use the asynch methods provided by the .net framework.
Your service's webmethod needs to be asynch as well. Otherwise a worker thread will be blocked until your external calls are done (it's still 1-2 seconds even if they run in parallel). And you only have 12 threads per CPU handling incoming requests (if your machine.config is set according to recommendation.) I.e. you would at most be able to handle 12 concurrent requests (times the # of CPUs). On the other hand if your web method is asynch the Begin will return pretty much instantenously and the thread returned to the worker thread pool ready to handle another incoming request, while your external calls are being waited on by the IO completion port, where they will be handled by threads from the IO thread pool, once they return.

Categories