I want to be able to load a user from a cloud database on each request and have that available on the request in a controller using asp.net mvc. The problem is the current framework does not support doing async operations from action filters. So OnActionExecuting, OnAuthorization methods do not allow me to do this.. for example I have the following code which DOES NOT work (so don't try it).. You get an exception : "An asynchronous module or handler completed while an asynchronous operation was still pending."
protected async override void OnAuthorization(AuthorizationContext filterContext)
{
var user = filterContext.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
HandleUnauthorizedRequest(filterContext);
return;
}
using (var session = MvcApplication.DocumentStore.OpenAsyncSession())
{
User currentUser = await session.LoadAsync<User>(user.Identity.Name);
if (currentUser == null)
{
HandleUnauthorizedRequest(filterContext);
return;
}
filterContext.HttpContext.Items["User"] = currentUser;
}
}
So is there any other way of being able to do this? I notice there is a begin execute method in the base Controller:
protected override IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state)
{
return base.BeginExecute(requestContext, callback, state);
}
Could I do it there possibly?
The question is three months old so I guess you've managed to work around this. Anyway, I'll add my solution here, as I had to do something similar.
I used the ToAsync
method from the ParallelExtensionsExtras library. This is my class:
public class AsyncControllerBase : Controller
{
protected override IAsyncResult BeginExecute(System.Web.Routing.RequestContext requestContext, AsyncCallback callback, object state)
{
return ExecuteCoreAsync(requestContext, state).ToAsync(callback, state);
}
protected override void EndExecute(IAsyncResult asyncResult)
{
IAsyncResult baseAsyncResult = ((Task<IAsyncResult>)asyncResult).Result;
base.EndExecute(baseAsyncResult);
}
protected virtual async Task<IAsyncResult> ExecuteCoreAsync(System.Web.Routing.RequestContext requestContext, object state)
{
await DoStuffHereOrInDerivedClassAsync();
var baseBeginExecuteCompletion = new TaskCompletionSource<IAsyncResult>();
AsyncCallback callback = ar =>
{
baseBeginExecuteCompletion.SetResult(ar);
};
// OnActionExecuting will be called at this point
var baseAsyncResult = base.BeginExecute(requestContext, callback, state);
await baseBeginExecuteCompletion.Task;
return baseAsyncResult;
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
}
}
See also this documentation from Microsoft on converting between Task and IAsyncResult.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With