2012-10-18 13 views
5

Desidero poter caricare un utente da un database cloud su ogni richiesta e avere quello disponibile sulla richiesta in un controller usando asp.net mvc. Il problema è che il framework corrente non supporta le operazioni asincrone dai filtri di azione. Quindi OnActionExecuting, i metodi OnAuthorization non mi permettono di fare questo .. per esempio ho il seguente codice che NON funziona (quindi non provarlo) .. Si ottiene un'eccezione: "Un modulo asincrono o un handler completati mentre un asincrono l'operazione era ancora in sospeso. "Esecuzione operazione Async asp.net mvc al di fuori dell'azione

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; 
    } 
} 

Quindi c'è un altro modo di essere in grado di farlo? Noto che esiste un metodo di esecuzione iniziale nel controller di base:

protected override IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state) 
{ 
    return base.BeginExecute(requestContext, callback, state); 
} 

Posso farlo lì forse?

+0

È possibile [votare per filtri azione asincrona qui] (https://aspnet.codeplex.com/workitem/9582). –

+0

Ho recentemente [pubblicato una libreria] (https://www.nuget.org/packages/Hydrogen.Extensions.Mvc5.Async) che aggiunge il supporto adeguato per i filtri asincroni (basato pesantemente sul codice in entrata da [ASP.NET MVC core] (https://github.com/aspnet/Mvc)). L'origine è anche disponibile qui: https://github.com/jdaigle/Hydrogen.Extensions.Mvc5. –

risposta

10

La domanda è di tre mesi, quindi credo che sia riuscito a risolvere il problema. Ad ogni modo, aggiungerò qui la mia soluzione, dato che dovevo fare qualcosa di simile.

Ho utilizzato alcuni metodi dalla libreria ParallelExtensionsExtras. Questa è la mia classe:

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); 
    } 
} 
+1

Si noti che 'Controller.Request' e molte altre proprietà sono' null' in 'DoStuffHereOrInDerivedClassAsync()', meglio passare 'RequestContext' come argomento per accedere ad alcune funzionalità. – deerchao

+0

Perché l'override "vuoto" di OnActionExecuting? –

+0

Ciao Dirk, sono passati due anni e mezzo da quando ho scritto questo, quindi onestamente non riesco a ricordare :) Forse l'intenzione originale era quella di sigillare l'override per evitare confusione nelle classi derivate - ma ho dimenticato di farlo davvero esso ?! –

Problemi correlati