I am trying to figure out how to create an asynchronous call from Application_Error Method in MVC.
I have an e-mail dll that I have written which sends out an e-mail via asynchronous call using Smtp Client.
The problem is that when I call SendEmail method in my dll I have conflict of needing to await for the call. Now if I try something like this:
protected async void Application_Error()
{
var await emailService.SendEmail("Hello World");
}
It will not work, the method will never even be called.
Is there a way for me to make an asynchronous call from a synchronous method? My research online hinted at HttpServerUtility.TransferRequest possibly being the answer but I could not figure out how to make it work with my request, it just doesn't make sense to me at the moment.
For those that may encounter this issue in the future, here is another solution that may be a bit more robust. Instead of using ThreadPool.QueueUserWorkItem() you can use HostingEnvironment.QueueBackgroundWorkItem(). Doing things this way, asks the server to make a bit more of an effort to complete these tasks before shutting down.
Here's an example from a recent project:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
HostingEnvironment.QueueBackgroundWorkItem(ct =>
ExceptionLogger.LogAsync(ex));
}
limitation of the dll, i cannot change it.
I don't know why that async call does not send an email. It should. There's a bug somewhere.
But a workaround is:
Task.Run(async () => { await emailService.SendEmail("Hello World"); }).Wait();
You could simplify and optimize this but this is the simplest way to bring the idea across. This pattern is always a safe way to synchronously call an async method. Not good for perf, but does not matter here because sending an email is 1000x more expensive than the overhead.
If you want to keep the async behavior you could remove the Wait. Although at that point I wonder why sending is not working in the first place. Is the bug triggered by the async behavior or is it always there?!
Related
I searched online but there is very little information regarding ThreadHelper.JoinableTaskFactory.RunAsync
If I have the following code, Test1 runs on MainThread:
public bool Test1()
{
// Do something here
ThreadHelper.JoinableTaskFactory.RunAsync(this.Test2);
// Do something else
return false;
}
private async Task Test2()
{
await TaskScheduler.Default;
// do something here
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
// do something here
}
Is it ok if the RunAsync has never been awaited on? What would happen if Test1 returns before Test2 finishes running?
Is it ok if the RunAsync has never been awaited on?
That depends. It's OK from JoinableTaskFactory's perspective. All the necessary continuations will continue -- it's just that your calling method won't wait for it to complete, which is the whole point of not awaiting it if you choose to do so.
But in general, it may not be healthy for your app. Consider the case that your async work is saving a file (or transmitting something over the network) and the user closes your app. Wouldn't you want the app to wait for it to finish before closing? As #GrzegorzSmulko said in his answer, the JoinableTaskFactory prescribes a pattern for blocking on shutdown (or disposal of your object) to ensure async work completes.
There's another reason to track your async work if you're in an app that hosts the CLR and shuts it down before exiting: you don't want managed threads running around doing arbitrary things when the AppDomain is being finalized or you'll find that your app crashes on shutdown. This is not a concern when you have a pure-managed app though, since it just exits without shutting down the CLR. It will not crash, but it will still abandon any half-done work.
All the foregoing is true in any app that you use JoinableTaskFactory for. If you happen to be using it within Visual Studio (I'm speaking generally here for a broader audience... I know your question specifically mentioned VS) then the rules are stressed more. You should track all your async work as prescribed in that section. You shouldn't have any "fire and forget" work.
The FileAndForget extension method is actually intended for internal Microsoft use since it sends errors to our telemetry servers. If you really want to just forget stuff, you can use the .Forget() extension method. But remember you should only use that after scheduling the work using an AsyncPackage.JoinableTaskFactory instance or another one that is tracking your async work for disposal. Don't use it on ThreadHelper.JoinableTaskFactory because that doesn't track async-and-forgotten work. So for example, don't do this:
ThreadHelper.JoinableTaskFactory.RunAsync(async () => { /* something async */ }).Forget();
The problem with the above is that the async work will not be tracked, and thus not block shutdown. You should do this instead:
myAsyncPackage.JoinableTaskFactory.RunAsync(async () => { /* something async */ }).Forget();
Or even better: just await the call, in which case you can use pretty much any JTF instance:
await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { /* something async */ });
But if you're in a context where you can use await, you often don't need JoinableTaskFactory.RunAsync at all, since if you can just await the code within the delegate itself. Some uncommon scenarios may require that you still track the async work with a JoinableTaskCollection where you might want to use await someJtf.RunAsync but normally you can just drop JTF use where you can naturally await your work.
According to Threading Cookbook for Visual Studio you should use ThreadHelper.JoinableTaskFactory.RunAsync() together with FileAndForget().
The potential problem is, that FileAndForget() is not available in VS2015, but only in VS2017+.
Is it ok if the RunAsync has never been awaited on?
I think it's not ok, you should use FileAndForget. But, I don't really know what to do for VS2015.
What would happen if Test1 returns before Test2 finishes running?
This should be pretty easy to test to make sure. I assume that Test2 will just finish later "But you also should be sure your async work finishes before your object claims to be disposed."
What is the simplest way to make an HTTP request? I don't need to read the answer, I just want to send a GET request to an url as simple as possible. I'm using .NET framework 3.5. Waiting for a response is not required either.
At this moment I'm using the following, but I'm wondering if there is a better (shorter/doesn't wait for a response) way.
((HttpWebRequest)WebRequest.Create("http://foo.bar/?q=test")).GetResponse();
Waiting for a response is not required either.
Be very careful with that requirement. People seem to love to "fire and forget" for performance reasons right up until there's something wrong with the system. Then they find that the "forget" part means that the system was explicitly designed not to handle error conditions.
Now, having said that, since you're using 3.0 and don't have the luxury of async or the TPL, you may simply be looking at starting a thread to do the work so that the invoked code returns immediately. (The "don't wait for a response" part.) Combine this with wrapping it in a handy method and you have the "short" part as well.
Maybe something like this:
public static void SendRequest(string url)
{
var thread = new Thread(ThisClass.SendRequest));
thread.Start(url);
// maybe do something to monitor the thread object?
}
private static void SendRequest(object url)
{
var response = ((HttpWebRequest)WebRequest.Create(string.Format("{0}", url))).GetResponse();
// You have a response, might as well examine it for success/failure
}
So consuming code would simply call:
ThisClass.SendRequest("http://foo.bar/?q=test");
The idea here is that consuming code doesn't need to wait for a response, but the thread can wait for the response and handle it accordingly. Even if "handling" it simply means doing nothing for success conditions.
I have a Xamarin.Forms application, with this code in my App class (yes, this is just a sample to demonstrate the issue):
public App()
{
BlobCache.ApplicationName = "MyApp";
BlobCache.EnsureInitialized();
// The root page of your application
MainPage = GetMainPage();
}
public object BlockingGetExternalUser()
{
return GetExternalUser().Result;
}
private async Task<object> GetExternalUser()
{
try
{
return await BlobCache.LocalMachine.GetObject<object>("user");
}
catch (KeyNotFoundException)
{
return null;
}
}
The Key "user" does not exist, so I would expect to get a KeyNotFoundException. However I never see this exception being thrown. Instead it just "hangs" and never returns from the await GetObject call.
I am running this on my phone with Android 5.0.
Any ideas how to fix this? Am I doing something fundamentally wrong?
Update: On a side note: Instead of immediately trying GetObject, one could try to check if the key actually exists in the cache and only then retrieve it from the cache. However, if I am not mistaken, there is no other way to do a check other than calling GetObject and catching the exception like in the sample above. For a scenario where one would just want to know if an item exists, that doesn't seem to be ideal. Maybe an "Exists()" method would be a nice to have in Akavache? Or maybe I am missing something?
Update2: Changing the example to not use an async method in the constructor. Just to prove a point that that is not the issue.
Update3: Removing the call from the constructor. When I call BlockingGetExternalUser from anywhere in my code, the await will still hang.
You're most certainly having a dead-lock. Quoting Synchronously waiting for an async operation, and why does Wait() freeze the program here:
The await inside your asynchronous method is trying to come back to the UI thread.
Since the UI thread is busy waiting for the entire task to complete, you have a > deadlock.
Note that your call to .Result implies a Task.Wait() somewhere.
There are two solutions: Either completely avoid the async methods, or wrap your code into a Task.Run like this:
public object BlockingGetExternalUser()
{
return Task.Run<object>(() => GetExternalUser().Result);
}
(I hope it's compiling I didn't verify in VS :)
By experience I tend to avoid async methods in combination with SQLite these days. Reason is that most SQLite wrapper libraries use the Task.Run anti-pattern to provide async wrappers around their methods while SQLite doesn't have any intrinsic notations of being asynchronous. Note though that it's perfectly fine for you to wrap things into Task.Run to make them asynchronous and that it's only an anti-pattern for library designers, suggesting to their users that methods are asynchronous when they're actually not. You can read more about this here: Task.Run as an anti-pattern?
Using async methods in a constructors (var externalUser = GetExternalUser().Result;) is considered as a bad code. You shouldn't use async methods in a class constructors. Read this: Can constructors be async?
You could try to change it to avoid deadlocks:
Func<Task> task = async () => { await GetExternalUser().ConfigureAwait(false); };
task().Wait();
... but I won't recommend it.
The general answers such as here and here to fire-and-forget questions is not to use async/await, but to use Task.Run or TaskFactory.StartNew passing in the synchronous method instead. However, sometimes the method that I want to fire-and-forget is async and there is no equivalent sync method.
Update Note/Warning: As Stephen Cleary pointed out below, it is dangerous to continue working on a request after you have sent the response. The reason is because the AppDomain may be shut down while that work is still in progress. See the link in his response for more information. Anyways, I just wanted to point that out upfront, so that I don't send anyone down the wrong path.
I think my case is valid because the actual work is done by a different system (different computer on a different server) so I only need to know that the message has left for that system. If there is an exception there is nothing that the server or user can do about it and it does not affect the user, all I need to do is refer to the exception log and clean up manually (or implement some automated mechanism). If the AppDomain is shut down I will have a residual file in a remote system, but I will pick that up as part of my usual maintenance cycle and since its existence is no longer known by my web server (database) and its name is uniquely timestamped, it will not cause any issues while it still lingers.
It would be ideal if I had access to a persistence mechanism as Stephen Cleary pointed out, but unfortunately I don't at this time.
I considered just pretending that the DeleteFoo request has completed fine on the client side (javascript) while keeping the request open, but I need information in the response to continue, so it would hold things up.
So, the original question...
for example:
//External library
public async Task DeleteFooAsync();
In my asp.net mvc code I want to call DeleteFooAsync in a fire-and-forget fashion - I don't want to hold up the response waiting for DeleteFooAsync to complete. If DeleteFooAsync fails (or throws an exception) for some reason, there is nothing that the user or the program can do about it so I just want to log an error.
Now, I know that any exceptions will result in unobserved exceptions, so the simplest case I can think of is:
//In my code
Task deleteTask = DeleteFooAsync()
//In my App_Start
TaskScheduler.UnobservedTaskException += ( sender, e ) =>
{
m_log.Debug( "Unobserved exception! This exception would have been unobserved: {0}", e.Exception );
e.SetObserved();
};
Are there any risks in doing this?
The other option that I can think of is to make my own wrapper such as:
private void async DeleteFooWrapperAsync()
{
try
{
await DeleteFooAsync();
}
catch(Exception exception )
{
m_log.Error("DeleteFooAsync failed: " + exception.ToString());
}
}
and then call that with TaskFactory.StartNew (probably wrapping in an async action). However this seems like a lot of wrapper code each time I want to call an async method in a fire-and-forget fashion.
My question is, what it the correct way to call an async method in a fire-and-forget fashion?
UPDATE:
Well, I found that the following in my controller (not that the controller action needs to be async because there are other async calls that are awaited):
[AcceptVerbs( HttpVerbs.Post )]
public async Task<JsonResult> DeleteItemAsync()
{
Task deleteTask = DeleteFooAsync();
...
}
caused an exception of the form:
Unhandled Exception: System.NullReferenceException: Object reference
not set to an instance of an object. at System.Web.ThreadContext.AssociateWithCurrentThread(BooleansetImpersonationContext)
This is discussed here and seems to be to do with the SynchronizationContext and 'the returned Task was transitioned to a terminal state before all async work completed'.
So, the only method that worked was:
Task foo = Task.Run( () => DeleteFooAsync() );
My understanding of why this works is because StartNew gets a new thread for DeleteFooAsync to work on.
Sadly, Scott's suggestion below does not work for handling exceptions in this case, because foo is not a DeleteFooAsync task anymore, but rather the task from Task.Run, so does not handle the exceptions from DeleteFooAsync. My UnobservedTaskException does eventually get called, so at least that still works.
So, I guess the question still stands, how do you do fire-and-forget an async method in asp.net mvc?
First off, let me point out that "fire and forget" is almost always a mistake in ASP.NET applications. "Fire and forget" is only an acceptable approach if you don't care whether DeleteFooAsync actually completes.
If you're willing to accept that limitation, I have some code on my blog that will register tasks with the ASP.NET runtime, and it accepts both synchronous and asynchronous work.
You can write a one-time wrapper method for logging exceptions as such:
private async Task LogExceptionsAsync(Func<Task> code)
{
try
{
await code();
}
catch(Exception exception)
{
m_log.Error("Call failed: " + exception.ToString());
}
}
And then use the BackgroundTaskManager from my blog as such:
BackgroundTaskManager.Run(() => LogExceptionsAsync(() => DeleteFooAsync()));
Alternatively, you can keep TaskScheduler.UnobservedTaskException and just call it like this:
BackgroundTaskManager.Run(() => DeleteFooAsync());
As of .NET 4.5.2, you can do the following
HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken => await LongMethodAsync());
But it only works within ASP.NET domain
The HostingEnvironment.QueueBackgroundWorkItem method lets you
schedule small background work items. ASP.NET tracks these items and
prevents IIS from abruptly terminating the worker process until all
background work items have completed. This method can't be called
outside an ASP.NET managed app domain.
More here: https://msdn.microsoft.com/en-us/library/ms171868(v=vs.110).aspx#v452
The best way to handle it is use the ContinueWith method and pass in the OnlyOnFaulted option.
private void button1_Click(object sender, EventArgs e)
{
var deleteFooTask = DeleteFooAsync();
deleteFooTask.ContinueWith(ErrorHandeler, TaskContinuationOptions.OnlyOnFaulted);
}
private void ErrorHandeler(Task obj)
{
MessageBox.Show(String.Format("Exception happened in the background of DeleteFooAsync.\n{0}", obj.Exception));
}
public async Task DeleteFooAsync()
{
await Task.Delay(5000);
throw new Exception("Oops");
}
Where I put my message box you would put your logger.
I need to make async request to web resource and use example from this page (link to full example):
HttpWebRequest myHttpWebRequest= (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
RequestState myRequestState = new RequestState();
myRequestState.request = myHttpWebRequest;
// Start the asynchronous request.
IAsyncResult result=
(IAsyncResult) myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback),myRequestState);
But when I am testing the application the execution freeze(on 2-3 sec) on the last line of this code (i can watch it using debugger).
Why? Is it my mistake or it is a standard behaviour of the function?
You can try, I m sure thats better
private void StartWebRequest(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.BeginGetResponse(new AsyncCallback(FinishWebRequest), request);
}
private void FinishWebRequest(IAsyncResult result)
{
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}
Because of chross thread of textbox'value,But this is wpf application i will retag this, btw you can use webclient like
private void tbWord_TextChanged(object sender, TextChangedEventArgs e)
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += HttpsCompleted;
wc.DownloadStringAsync(new Uri("http://en.wikipedia.org/w/api.php?action=opensearch&search=" + tbWord.Text));
}
private void HttpsCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
//do what ever
//with using e.Result
}
}
It's the standard behaviour.
From the documentation on HttpWebRequest.BeginGetResponse Method:
The BeginGetResponse method requires some synchronous setup tasks to complete (DNS resolution, proxy detection, and TCP socket connection, for example) before this method becomes asynchronous. [...]
it might take considerable time (up to several minutes depending on network settings) to complete the initial synchronous setup tasks before an exception for an error is thrown or the method succeeds.
To avoid waiting for the setup, you can use
HttpWebRequest.BeginGetRequestStream Method
but be aware that:
Your application cannot mix synchronous and asynchronous methods for a particular request. If you call the BeginGetRequestStream method, you must use the BeginGetResponse method to retrieve the response.
The response occurs on a separate thread. Winforms are not multi-thread safe, so you're going to have to dispatch the call on the same thread as the form.
You can do this using the internal message loop of the window. Fortunately, .NET provides a way to do this. You can use the control's Invoke or BeginInvoke methods to do this. The former blocks the current thread until the UI thread completes the invoked method. The later does so asynchronously. Unless there is cleanup to do, you can use the latter in order to "fire and forget"
For this to work either way, you'll need to create a method that gets invoked by BeginInvoke, and you'll need a delegate to point to that method.
See Control.Invoke and Control.BeginInvoke in the MSDN for more details.
There's a sample at this link: https://msdn.microsoft.com/en-us/library/zyzhdc6b(v=vs.110).aspx
Update: As I'm browsing my profile because I forgot i had an account here - i noticed this and I should add: Anything past 3.5 or when they significantly changed the asynchronous threading model here is out of my wheelhouse. I'm out professionally, and while I still love the craft, I don't follow every advancement. What I can tell you is this should work in all versions of .NET but it may not be the absolute pinnacle of performance 4.0 and beyond or on Mono/Winforms-emulation if that's still around. On the bright side, any hit usually won't be bad outside server apps, and even inside if the threadpool is doing its job. So don't focus optimization efforts here in most cases, and it's more likely to work on "stripped down" platforms you see running things like C# mobile packages although I'd have to look to be sure and most don't run winforms but some spin message loops and this works there too. Basically to bottom line, it's not the "best answer" for the newest platforms in every last case. But it might be more portable in the right case. If that helps one person avoid making a design error, then it was worth the time I took to write this. =)
You can use BackgroundWorker add do the whole thing in DoWork