I have two methods on the page. One AddMessageToInboxOutbox(params[]) and other one SendNewMessageMail(params[]).
Once user sends an message to other other first message is added to DB and then sent to recipient's email. Sometimes SMTP is heavy loaded and it takes up to 5 seconds to get answer from it. I want to enclose SendNewMessageMail(params[]) with async call using other thread or something. I have never done that.
How do i perform this action right in ASP.NET?
You can use a delegate to call the method asynchronously:
delegate void SendMailAsync(params object[] args);
static void Main()
{
SendMailAsync del = new SendMailAsync(SendMail);
del.BeginInvoke(new object[] { "emailAddress" }, null, null);
}
static void SendMail(params object[] args)
{
// Send
}
This will use the ThreadPool to assign another thread. In my example, I'm also not registering a callback. Note that this callback, if specified, will be placed onto an unknown ThreadPool thread. Calling EndInvoke on the delegate reference del will block until it completes.
EndInvoke takes the IAsyncResult object that is returned from the BeginInvoke method, if you do this, keep references to the del and IAsyncResult. Also, this isn't specific to ASP.NET.
Note: multi-threading is a powerful mechanism and an in-depth subject to learn. Coupling multi-threading with ASP.NET is arguably more involved than, say, a WinForms application - due to the page lifecycle etc. I'd advise reading up on the multi-threading topic as a whole too.
Alternatively, have a look at ParamaterizedThreadStart
Related
C# ASP.NET 3.5
Is it possible to "fire and forget" a method in a web service that is not asynchronous or one-way?
There is a method that returns a value (after some processing), which I don't need. It is used by another group (who wrote the service). Basically, it just notifies that user x did action y. I just need to call the method and move on without waiting for the result.
I tried using a BackgroundWorker() with RunWorkerAsync, but the method does not fire for some reason. I cannot change the web service method as I have no access to their code. Should I be using BackgroundWorker, Invoke, ThreadPool, something else? I don't need the result returned, and I don't need to know if it fails. Basically, call the method, and if it works, great. If not, I don't want to stop or slow processing down.
public static void Test()
{
var worker = new BackgroundWorker();
worker.DoWork += Test2;
worker.RunWorkerAsync(new object[] {12345, "test"});
}
private static void Test2(object sender, DoWorkEventArgs e)
{
// Write to log that we got into the method - does not
object[] args = e.Argument as object[];
int num = Convert.ToInt32(args[0]);
string name = (string)args[1];
// call web service method here....
}
Intsead of using Background Worker you can try the following
public static void Test()
{
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
Test2(new object[] { 12345, "test" });
});
}
private static void Test2(object data)
{
// Write to log that we got into the method - does not
object[] args = data as object[];
int num = Convert.ToInt32(args[0]);
string name = (string)args[1];
// call web service method here....
}
The feature that is requested, by definition IS WCF OneWay. It is impossible to implement the required behavior completely client-side.
IIS by default (a common host of WCF services) is allowed to kill any process that was kicked off by a closed connection. This means that the client must stay connected for the duration of the process (which in effect means waiting for the result). Additionally it is possible the request can timeout and the "fire and forget" process is killed off.
If you only want to reduce the resources taken up at the client to the minimum whilst the request is in flight I would run the request asynchronously. If you only have access to .net<=4.0 then the easiest way to do this is to generate the async calls (I mean APM async and NOT async/await/TPL async) using the "add service reference" option and tick the "generate async methods" option.
You would have to also learn the APM programming model (which is pretty nasty).
Alternatively you could run the WCF call on a separate Thread. But note, this uses significant additional resources.
There is a document here on Asysn/Sync wfc calls. http://msdn.microsoft.com/en-us/library/ms734701.aspx.
We are calling WCF services asyncronously.
public partial class ServiceClient : System.ServiceModel.ClientBase<MyService>, MyService
{
......
}
ServiceClient _serviceclient;
void Getproducts(string filter, string augument, EventHandler<GetCompletedEventArgs> callback)
{
_serviceclient.GetAsyncGetproducts(filter, argument, callback);
}
I want to the Getproducts function to be synchronous. What is the best way to achieve this like the following
void Getproducts(string filter, string augument, EventHandler<GetCompletedEventArgs> callback)
{
_serviceclient.GetAsyncGetproducts(filter, argument, callback);
//wait until callback comes back and return
}
EDIT: The proxy is providing any synchronous calls
You cannot make synchronous networking requests in Silverlight from the UI thread. There's no going around that. Even if you try to trick the asynchronous methods into behaving synchronously, it will not work. That's because if that were possible, the UI thread would be blocked, and the application would appear to be frozen. This happens because the responses to networking requests in SL are always delivered to the UI thread; if you wait for it on the UI thread itself, then you create a deadlock.
You essentially have two options: the preferred one is to actually go the asynchronous route. It's hard at first, if you're only used to synchronous programming, but it's a very valuable skill to have. The other option is to make the call on a background thread. I've tried it and it works, and some people have blogged about it, so you can try it as well. But AFAIK it's not officially supported.
Rather than just passing the callback parameter as the callback you'll want to assign your own callback that executes that method in addition to doing something else. You effectively just need to trigger an event of some sort. I have demonstrated one way using tasks, but you could just as easily use an auto reset event or one of any number of other synchronization methods.
void Getproducts(string filter, string augument, EventHandler<GetCompletedEventArgs> callback)
{
var tcs = new TaskCompletionSource<bool>();
_serviceclient.GetAsyncGetproducts(filter, argument, args =>
{
callback(args);
tcs.SetResult(true);
});
tcs.Task.Wait();
}
I'm trying to convert this method ExportTo3rdParty() to use an AsyncController:
public JsonResult SaveSalesInvoice(SalesInvoice invoice)
{
SaveInvoiceToDatabase(invoice); // this is very quick
ExportTo3rdParty(invoice); // this is very slow and should be async
}
But the ExportTo3rdParty() method uses HttpContext.Current in multiple places (far too many to change - the original coder did not use enough dependency injection). For example it calls GetDefaultCurrency(). Will this still work when ExportTo3rdParty() is called through an AsyncController?
public Currency GetDefaultCurrency()
{
Currency currency;
string key = string.Format("DefaultCurrency_{0}",
HttpContext.Current.User.Identity.Name);
currency = HttpRuntime.Cache.Get(key) as Currency;
if (currency == null)
{
currency = LookupDefaultCurrency();
HttpRuntime.Cache[key] = currency;
}
}
I know that if I use Thread.Start that I can not access HttpContext.Current. But what about an AsyncController?
So let me ask you why you want to use an Async controller?
Do you think it's going to be faster? Just because something it slow doesn't mean you need to make it async. In fact you'll most likely find that the method is slower when run async due to thread management/context switching overheads.
From what little I can understand from the two methods you've shown. I'm guessing that ExportTo3Party can basically be done "out of band". That is by an external process. So what you should be doing is either use MSMQ to queue the job (this returns immediately) so it's non-blocking. And have some other process/application process the queued jobs. This other process could be a regular Console application that is kept running on the server (using Task Sheduler) and it simply processes jobs as soon as they arrive in the queue.
Or even simpler (if you've not used MSMQ), simply execute an external application (console app again) and not wait for the app to exit. So you can use System.Diagnostics.Process to start the process and don't WaitForExit.
Both of these alternatives are the right/better way to implement what I think ExportTo3rdParty is doing. Seeing that you're not waiting on a response from this method ot return it.
If I haven't convinced you yet, then:
From MSDN documentation
If an asynchronous action method calls
a service that exposes methods by
using the BeginMethod/EndMethod
pattern, the callback method (that is,
the method that is passed as the
asynchronous callback parameter to the
Begin method) might execute on a
thread that is not under the control
of ASP.NET. In that case,
HttpContext.Current will be null, and
the application might experience race
conditions when it accesses members of
the AsyncManager class such as
Parameters. To make sure that you have
access to the HttpContext.Current
instance and to avoid the race
condition, you can restore
HttpContext.Current by calling Sync()
from the callback method.
If the callback completes
synchronously, the callback will be
executed on a thread that is under the
control of ASP.NET and the operations
will be serialized so there are no
concurrency issues. Calling Sync()
from a thread that is already under
the control of ASP.NET has undefined
behavior.
The ActionCompleted method will always
be called on a thread that is under
the control of ASP.NET. Therefore, do
not call fSync() from that method.
The callback that you pass to the
Begin method might be called using a
thread that is under the control of
ASP.NET. Therefore, you must check for
this condition before you call Sync().
If the operation completed
synchronously (that is, if
CompletedSynchronously is true), the
callback is executing on the original
thread and you do not have to call
Sync(). If the operation completed
asynchronously (that is,
CompletedSynchronously is false), the
callback is executing on a thread pool
or I/O completion port thread and you
must call Sync().
http://msdn.microsoft.com/en-us/library/ee728598.aspx
I've noticed the following pattern recently, but I don't entirely grasp the usage of the CompletedSynchronously property:
IAsyncResult channelOpenResult = channel.BeginOpen(new AsyncCallback(OnOpenCompleteChannel), channel);
if (channelOpenResult.CompletedSynchronously)
{
CompleteOpenChannel(channelOpenResult);
}
And then again, in the callback:
void OnOpenCompleteChannel(IAsyncResult result)
{
if (result.CompletedSynchronously)
return;
else
CompleteOpenChannel(result);
}
And somewhere in the code there is of course a function:
void CompleteOpenChannel(IAsyncResult result) ...
Is this a way to handle the asynchronous call differently depending on whether it completes directly or not? But why use it in this case, since the AsyncCallback always will be called (will it?)?
Could someone give an example where the call is made synchronously?
See this blog. A common pattern does async work in a loop, and checking CompletedSynchronously helps avoid the case where you get 'unlucky' and a bunch of async calls happen to complete sync and you risk StackOverflowException. (E.g. if you're reading data over the network, and the data you're reading has already come over the wire and is buffered, your async call may complete synchronously, which means your callback is called on the same thread (with a taller stack), which means you better not schedule another async call in a loop.)
According to this document you can supply the call with a synchronous and ASync callback, and only if the call was not handled synchronously, will it call the ASync methods. I do not think this is really applicable to Silverlight (because all Silverlight calls are ASync to a degree) but is probably used more for custom factories in other .NET applications.
Hope this helps.
I'm making asynchronous web service calls from a C# app:
{
//Put UI in 'loading' state
...
//Now call web service
webServiceProxy.BeginMyMethod(param, new AsyncCallback(MyCallback), null);
}
private void MyCallback(IAsyncResult res)
{
...
//process result
// Put UI back in normal state (yes I'm marshalling back to the UI thread)
}
The main thread puts the app in a "waiting" mode, and then the end of the Callback function re-enables the controls. I'm seeing a bug that occasionally, the UI is stuck forever in the loading mode.
Now there may just be a bug in the callback code (there's quite a bit there), but my question to the community here is this:
Is "MyCallback" GUARANTEED to be called? Presuming that "BeginMyMethod" didn't throw an exception, can I be sure that MyCallback will be executed? I'm seeing a "CompletedSynchronously" and "IsCompleted" on the IAsyncResult returned by the BeginXXX functions, but I'm not sure if that's important or not.
Yes, the callback is guaranteed to be called. The callback is what permits asynchronous code using the Begin* / End* pattern to be written in a continuation-passing style.
You must call the corresponding End* method in your callback (normally, the first thing in the callback), however. It is how the asynchronous method signals an exception that may have occurred during the call, for one thing, as well as the way to get a result out (if any).
Coding the asynchronous pattern using anonymous delegates when using C# 2.0 is sometimes more elegant, and permits writing of the post-call continuation close to the initiation of the call, as well as permitting much easier data sharing through captured variables, providing that appropriate synchronization measures are used.
Ref: http://msdn.microsoft.com/en-us/library/ms228972.aspx:
Applications that can do other work while waiting for the results of an asynchronous operation should not block waiting until the operation completes. Use one of the following options to continue executing instructions while waiting for an asynchronous operation to complete:
Use an AsyncCallback delegate to process the results of the asynchronous operation in a separate thread. This approach is demonstrated in this topic.
[...]
The AsyncCallback will be called regardless of whether the operation was completed synchronously or asynchronously.
I believe the callback is not guaranteed to be called if the CompletedSynchronously property is true.