I have a project that uses Microsoft Unity and Web API 2. It works great and there are no problems with it. However when I try to use async/await
public async Task<IHttpActionResult> Post(PackageOrderDto dto)
{
try
{
newOrderNumber = await _apiPlaceOrder.Save(dto));
}
catch (ApiValidationFailedException apiValidationFailedException)
{
return BadRequest(apiValidationFailedException);
}
return Ok("VF" + newOrderNumber);
}
I get a ResolutionFailedException with this message:
Exception is:
InvalidOperationException - The PerRequestLifetimeManager can only be
used in the context of an HTTP request. Possible causes for this error
are using the lifetime manager on a non-ASP.NET application, or using
it in a thread that is not associated with the appropriate
synchronization context.
The ApiPlaceOrder is managed using UnityHierarchicalDependencyResolver.
The code works fine when async/await is not used.
Any ideas how to get Unity to play nice with async/await?
I've stripped the code for _apiPlaceOrder.Save(...) right back to this to try and isolate the problem and I still get the same issue:
public class ApiPlaceOrder
{
public async Task<int> Save(PackageOrderDto dto)
{
await Task.Delay(10000);
return 1;
}
}
You will get this error when you are using PerRequestLifetimeManager in the Unity.Mvc project and HttpContext.Current is null. That will occur when you are no longer on the originating thread of the http request.
Check your code for any occurrences of await fooTask.ConfigureAwait(false) or something that is creating a new thread or acquiring a thread from the thread pool. Hook up a debugger and put HttpContext.Current in your watch window and step through your code until that property switches to null.
Related
I want to run a method asynchronously from my web api code but I am not getting the desired behavior.
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
I have tried various combination of calls with await and async but not getting any success still.
I might not be understanding the concept of async/await correctly.
Can you please let me know what's the mistake I am making?
My controller code is below
[HttpGet("{id}")]
public string Get(int id)
{
PracticeAsync p = new PracticeAsync();
p.LongCallMethod();
return "Success";
}
The code for the class PracticeAsync is below:
public class PracticeAsync
{
public async Task LongCallMethod()
{
var x = await CallThis();
}
public async Task<dynamic> CallThis()
{
Thread.Sleep(10000); //DB call
return "done";
}
}
I am trying to do the LongCallMethod in an asynchronous way. So that I am able to return success to my user before the LongCallMethod completes.
That's not how async works.
You'll need to use SignalR or a proper distributed architecture. Specifically, your webapp should place its work into a reliable queue, and have an independent service read from that queue and do the work. ASP.NET was designed to serve web requests, and has severe reliability limitations if you try to force it to do otherwise.
I'm trying to use LinqToTwitter to post newsarticles to Twitter from an ASP.NET CMS. I've created a static class that will handle it for me as the outcome will be logged anyway and won't affect the rest of the website. However, when I try to run it and post to Twitter, an exception occurs:
System.InvalidOperationException: An asynchronous module or handler completed while an asynchronous operation was still pending
The full class:
public static class SocialTwitter
{
internal async static void PostTwitter(string message)
{
await Post(message);
}
private async static Task Post(string message)
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["TwitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["TwitterConsumerSecret"],
AccessToken = ConfigurationManager.AppSettings["TwitterToken"],
AccessTokenSecret = ConfigurationManager.AppSettings["TwitterTokenSecret"]
}
};
await auth.AuthorizeAsync();
TwitterContext t = new TwitterContext(auth);
//Exception occurs here
Status tweet = await t.TweetAsync(Uri.EscapeDataString(message));
if (tweet != null)
{
Util.Log.Info(string.Format("Status posted: ({0}) {1}, {2}", tweet.StatusID, tweet.User.Name, tweet.Text));
}
else
{
Util.Log.Info("Error occurred posting status to Twitter");
}
}
}
The weird part (for me at least) is that I use the function as described in the tooltip and documentation of LinqToTwitter. I get that some function is completed while another was still running but isn't that what the "await" keyword is for?
I tried cutting out the PostTwitter function or the code after the point of failure but still the same result. I've searched a lot for a solution but I might just be terrible at searching or searching in the wrong direction. I even registered on SO just to ask this question! :D
The culprit here is the fact that you're invoking Post with an async void method:
internal static async void PostTwitter
Async void functions exists solely for event handling, and have very odd and unpredictable error handling when used outside of this context. See this MSDN article for information.
Switch your async void method to an async Task method and some actual errors may start to bubble to the surface:
internal static async Task PostTwitter
Stephen Cleary actually goes into this problem in great detail in another SO post. To quote from him directly regarding the behavior of asynchronous methods:
Historically, ASP.NET has supported clean asynchronous operations since .NET 2.0 via the Event-based Asynchronous Pattern (EAP), in which asynchronous components notify the SynchronizationContext of their starting and completing
Whenever your code calls into SocialTwitter.PostTwitter, the PostTwitter method notifies the SynchronizationContext that it's started, bypassing whichever framework you're using completely and going straight to the ASP.NET core. The PostTwitter method than starts the async Post method, which also notifies the SynchronizationContext that it has started.
The ASP.NET frameworks understand how to wait for Tasks, but, excluding WinForms and WebForms in very specific situations, know little about how to handle async void methods. Thus the framework believes the async void to be complete and it attempts to notify the SychronizationContext that the async void method has finished, even though the async void method spawned an async Task method that's still running. As part of a series of safety nets designed specifically to catch errors like this, the SynchronizationContext throws the InvalidOperationException that you've been seeing.
I am working with async actions and use the HttpContext.Current.User like this
public class UserService : IUserService
{
public ILocPrincipal Current
{
get { return HttpContext.Current.User as ILocPrincipal; }
}
}
public class ChannelService : IDisposable
{
// In the service layer
public ChannelService()
: this(new Entities.LocDbContext(), new UserService())
{
}
public ChannelService(Entities.LocDbContext locDbContext, IUserService userService)
{
this.LocDbContext = locDbContext;
this.UserService = userService;
}
public async Task<ViewModels.DisplayChannel> FindOrDefaultAsync(long id)
{
var currentMemberId = this.UserService.Current.Id;
// do some async EF request …
}
}
// In the controller
[Authorize]
[RoutePrefix("channel")]
public class ChannelController : BaseController
{
public ChannelController()
: this(new ChannelService()
{
}
public ChannelController(ChannelService channelService)
{
this.ChannelService = channelService;
}
// …
[HttpGet, Route("~/api/channels/{id}/messages")]
public async Task<ActionResult> GetMessages(long id)
{
var channel = await this.ChannelService
.FindOrDefaultAsync(id);
return PartialView("_Messages", channel);
}
// …
}
I have the code recently refactored, previously I had to give the user on each call to the service.
Now I read this article https://www.trycatchfail.com/2014/04/25/using-httpcontext-safely-after-async-in-asp-net-mvc-applications/ and I’m not sure if my code still works.
Has anyone a better approach to handle this? I don’t want to give the user on every request to the service.
As long as your web.config settings are correct, async/await works perfectly well with HttpContext.Current. I recommend setting httpRuntime targetFramework to 4.5 to remove all "quirks mode" behavior.
Once that is done, plain async/await will work perfectly well. You'll only run into problems if you're doing work on another thread or if your await code is incorrect.
First, the "other thread" problem; this is the second problem in the blog post you linked to. Code like this will of course not work correctly:
async Task FakeAsyncMethod()
{
await Task.Run(() =>
{
var user = _userService.Current;
...
});
}
This problem actually has nothing to do with asynchronous code; it has to do with retrieving a context variable from a (non-request) thread pool thread. The exact same problem would occur if you try to do it synchronously.
The core problem is that the asynchronous version is using fake asynchrony. This inappropriate, especially on ASP.NET. The solution is to simply remove the fake-asynchronous code and make it synchronous (or truly asynchronous, if it actually has real asynchronous work to do):
void Method()
{
var user = _userService.Current;
...
}
The technique recommended in the linked blog (wrapping the HttpContext and providing it to the worker thread) is extremely dangerous. HttpContext is designed to be accessed only from one thread at a time and AFAIK is not threadsafe at all. So sharing it among different threads is asking for a world of hurt.
If the await code is incorrect, then it causes a similar problem. ConfigureAwait(false) is a technique commonly used in library code to notify the runtime that it doesn't need to return to a specific context. Consider this code:
async Task MyMethodAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
var context = HttpContext.Current;
// Note: "context" is not correct here.
// It could be null; it could be the correct context;
// it could be a context for a different request.
}
In this case, the problem is obvious. ConfigureAwait(false) is telling ASP.NET that the rest of the current method does not need the context, and then it immediately accesses that context. When you start using context values in your interface implementations, though, the problem is not as obvious:
async Task MyMethodAsync()
{
await Task.Delay(1000).ConfigureAwait(false);
var user = _userService.Current;
}
This code is just as wrong but not as obviously wrong, since the context is hidden behind an interface.
So, the general guideline is: use ConfigureAwait(false) if you know that the method does not depend on its context (directly or indirectly); otherwise, do not use ConfigureAwait. If it's acceptable in your design to have interface implementations use the context in their implementation, then any method that calls an interface method should not use ConfigureAwait(false):
async Task MyMethodAsync()
{
await Task.Delay(1000);
var user = _userService.Current; // works fine
}
As long as you follow that guideline, async/await will work perfectly with HttpContext.Current.
Async is fine. The problem is when you post the work to a different thread. If your application is setup as 4.5+, the asynchronous callback will be posted in the original context, so you'll also have the proper HttpContext etc.
You don't want to access shared state in a different thread anyway, and with Tasks, you rarely need to handle that explicitly - just make sure you put all your inputs as arguments, and only return a response, rather than reading or writing to a shared state (e.g. HttpContext, static fields etc.)
There is no problem, if your ViewModels.DisplayChannel is a simple object without additional logic.
A problem may occur, if the result of your Task references to "some context objects", f.e. to HttpContext.Current. Such objects are often attached to the thread, but entire code after await may be executed in another thread.
Keep in mind, that UseTaskFriendlySynchronizationContext doesn't solve all your problems. If we are talking about ASP.NET MVC, this setting ensures that Controller.HttpContext contains correct value as before await as after. But it doesn't ensure that HttpContext.Current contains correct value, and after await it still can be null.
I am writing an ASP.NET MVC 5 application which among others uses web services to get/process some the data.
The data flow of the app is following: MVC Action -> Service B -> ExtSvc which is async wrapper of a web service
Here are some examples:
public class ExtSvc
{
//Convert Event based async pattern to task based async pattern:
private Task<Response> ProcessExtRequestAsync(Request request)
{
TaskCompletionSource<Response> taskCompletionSource =
AsyncServiceClientHelpers.CreateSource<Response>(request);
ProcessRequestCompletedEventHandler handler = null;
handler =
(sender, e) =>
AsyncServiceClientHelpers.TransferCompletion(
taskCompletionSource,
e,
() => e.Result,
() => this.Service.ProcessRequestCompleted -= handler);
this.Service.ProcessRequestCompleted += handler;
try
{
this.Service.ProcessRequestAsync(request, taskCompletionSource);
}
catch (Exception)
{
this.Service.ProcessRequestCompleted -= handler;
taskCompletionSource.TrySetCanceled();
throw;
}
return taskCompletionSource.Task;
}
//Usage:
public async Task<Response> UpdateRequest(some arguments)
{
//Validate arguments and create a Request object
var response = await this.ProcessExtRequestAsync(request)
.ConfigureAwait(false);
return response;
}
}
Class B is the one that uses ExtSvc in a synchronous way
public class B
{
public ExtSvc service {get; set;}
public Response Update(arguments)
{
//some logic
var result = this.ExtSvc.UpdateRequest(arguments).Result;
//some logic
return result
}
}
Finally the MVC action (also synchronous)
public ActionResult GetResponse(int id)
{
//some logic
B.Update(id);
//some logic
return View(...);
}
The described flow throws an error
A first chance exception of type 'System.InvalidOperationException'
occurred in System.Web.dll
Additional information: An asynchronous operation cannot be started at
this time. Asynchronous operations may only be started within an
asynchronous handler or module or during certain events in the Page
lifecycle. If this exception occurred while executing a Page, ensure
that the Page is marked <%# Page Async="true" %>. This exception may
also indicate an attempt to call an "async void" method, which is
generally unsupported within ASP.NET request processing. Instead, the
asynchronous method should return a Task, and the caller should await
it.
on the following line of ExtSvc : this.Service.ProcessRequestAsync(request, taskCompletionSource); ProcessRequestAsync is a void method
So it corresponds to:
This exception may
also indicate an attempt to call an "async void" method, which is
generally unsupported within ASP.NET request processing
I know that converting GetResponse MVC action to asynchronous (by using async/await) and also converting the B class that actually uses ExtSvc to be asynchronous resolves the issue.
BUT my questions is:
If I can't change the signature of B class (because of an interface it implements) to return Task<Response> instead of Response it basically means that I can't use async/await on it so how this issue could be resolved?
ProcessRequestAsync is void but it's not async void. It looks like it's an EBAP API. EBAP components generally use AsyncOperationManager/AsyncOperation, which in turn do use SynchronizationContext to notify the underlying platform of the asynchronous operation (the last link is to my MSDN article on SynchronizationContext).
The exception you're seeing is because ASP.NET sees that notification (of the asynchronous operation starting) and says "whoa, there, fella. You're a synchronous handler! No async for you!"
Hands-down, the best approach is to make all methods asynchronous that should be asynchronous. This means B.Update should be B.UpdateAsync. OK, so there's an interface IB.Update - just change the interface to IB.UpdateAsync too. Then you're async all the way, and the code is clean.
Otherwise, you'll have to consider hacks. You could use Task.Run as #neleus suggested - that's a way of avoiding the ASP.NET SynchronizationContext so it doesn't "see" the asynchronous operation starting - but note that "ambient context" such as HttpContext.Current and page culture is lost. Or, you could (temporarily) install a new SynchronizationContext() onto the request thread - which also avoids the ASP.NET SynchronizationContext while staying on the same thread - but some ASP.NET calls assume the presence of the ASP.NET SynchronizationContext and will fail.
There's another hack you could try; it might work but I've never done it. Just make your handler return a Task<ActionResult> and use Task.FromResult to return the view: return Task.FromResult<ActionResult>(View(...)); This hack will tell ASP.NET that your handler is asynchronous (even though it's not).
Of course, all of these hacks have the primary disadvantage that you're doing sync-over-async (this.ExtSvc.UpdateRequest(arguments).Result), which means you'll be using one extra unnecessary thread for the duration of each request (or two threads, if you use the Task.Run hack). So you will be missing all the benefits of using asynchronous handlers in the first place - namely, scalability.
I think the error occurs because your code
this.Service.ProcessRequestAsync(request, taskCompletionSource);
actually calls SynchronizationContext's OperationStarted method that results in error as described here.
As a possible solution you can call your action on ThreadPoolSynchronizationContext
public async Task<ActionResult> GetResponse(int id)
{
//some logic
await Task.Run(() => { B.Update(id); });
//some logic
return View(...);
}
but it adds some overhead of utilizing a thread from the pool.
I have the following mvc action.
public async Task<JsonResult> DoSomeLongRunningOperation()
{
return await Task.Run(() =>
{
//Do a lot of long running stuff
//The underlying framework uses the HttpContext.Current.User.Identity.Name so the user is passed on the messagebus.
}
}
In the task the HttpContext gets null. We did a lot of tricking, but nothing assures us of the HttpContext being available always in our new thread.
Is there a solution to use HttpContext within out async tasks?
In our IocContainer we have registered the following object which passes the username to the framework.
public class HttpContextUserIdentityName : ICredentials
{
public string Name
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
This code is called in a lot of places before persisting to the database.
We need either another way of getting the username of the user initiated the webrequest or fix the issue with the HttpContext being null.
Because the persisting to the database happens in the Task I can't access the HttpContext before entering the task.
I also can't think of a safe way to temporary persist the username so I can implement another ICredentials service object.
You almost never want to use Task.Run in an ASP.NET method.
I think the cleanest solution (but the most work) is to implement async-compatible interfaces at your other layers:
public async Task<JsonResult> DoSomeLongRunningOperation()
{
//Do a lot of long running stuff
var intermediateResult = await DoLongRunningStuff();
return await DetermineFinalResult(intermediateResult);
}
You should get whatever information you need from the current context before you start the new thread. In this case, add something like:
string username = HttpContext.Current.User.Username;
before Task.Run and then use that inside of the other thread.
On a side note, as it stands, there's no reason to await the task. You can just return the task directly and not mark the method as Async.
If you need to access the Response object, which will presumably to utilize the results of the long running operation and thus can't be before Task.Run you should do so after the Task.Run (but ensure that the task is awaited). If you end up doing this then you can't do what I suggested in my previous paragraph.
I would try passing in the reference to the HttpContext as the state object, because that should create a new instance of that object on the stack for the thread that executes the work. Instead of using Task.Run, use
return await Task.Factory.StartNew((ctx) =>
{
var context = (HttpContext)ctx;
//Do stuff
}, httpContextObject);
Task.Run and Task.Factory.StartNew return immediately, so asp.net continues on in the event lifecycle in the worker thread that is handling the request while your thread is operating on the object that has already been disposed.