J'ai le code de test WebAPI suivant, je n'utilise pas WebAPI en production mais j'ai fait cela à cause d'une discussion que j'ai eue sur cette question: Question WebAPI Async
Quoi qu'il en soit, voici la méthode WebAPI incriminée:
public async Task<string> Get(int id)
{
var x = HttpContext.Current;
if (x == null)
{
// not thrown
throw new ArgumentException("HttpContext.Current is null");
}
await Task.Run(() => { Task.Delay(500); id = 3; });
x = HttpContext.Current;
if (x == null)
{
// thrown
throw new ArgumentException("HttpContext.Current is null");
}
return "value";
}
J'avais ici cru que la deuxième exception est attendue parce que lorsque le sera await
terminé, ce sera probablement sur un thread différent où, en HttpContext.Current
tant que variable de thread statique, ne sera plus résolu à la valeur appropriée. Maintenant, en fonction du contexte de synchronisation, il pourrait en fait être forcé de revenir au même thread après l'attente, mais je ne fais rien d'extraordinaire dans mon test. Ceci est juste une utilisation simple et naïve de await
.
Dans les commentaires d'une autre question, on m'a dit que cela HttpContext.Current
devrait être résolu après une attente. Il y a même un autre commentaire sur cette question indiquant la même chose. Alors qu'est-ce qui est vrai? Doit-il se résoudre? Je pense que non, mais je veux une réponse faisant autorité à ce sujet parce que async
et await
est suffisamment nouveau pour que je ne trouve rien de définitif.
TL; DR: Est-ce HttpContext.Current
potentiellement null
après un await
?
la source
AspNetSynchronizationContext
ça qui s'occupeHttpContext
, nonawait
. De plus, le rappel de continuation pourawait
peut (et probablement se produira) sur un thread différent pour le modèle d'exécution de l'API Web..ConfigureAwait(false)
quelque chose sur toute la ligne. Il n'y a pas de demande ou de contrôleur explicitement transmis via la couche métier, car celui-ci n'est pas compatible Web. Ceci est utile par exemple pour un module de journalisation qui peut injecter les détails de la requête lorsque la logique métier écrit un génériqueTraceInformation
.Réponses:
Veuillez vous assurer que vous écrivez une application ASP.NET 4.5 et ciblez 4.5.
async
etawait
ont un comportement indéfini sur ASP.NET, sauf si vous exécutez sur 4.5 et utilisez le nouveau contexte de synchronisation "convivial pour les tâches".En particulier, cela signifie que vous devez soit:
httpRuntime.targetFramework
sur4.5
, ouappSettings
, réglezaspnet:UseTaskFriendlySynchronizationContext
surtrue
.Plus d'informations sont disponibles ici .
la source
<httpRuntime targetFramework="4.5" />
est ce qui a résolu le problème, merci de préciser.targetFramework
sur 4.5.1 ou 4.5, mais async sur 4.5.1 devrait fonctionner correctement.Comme @StephenCleary l'a correctement souligné, vous en avez besoin dans votre web.config:
<httpRuntime targetFramework="4.5" />
Lorsque j'ai résolu ce problème pour la première fois, j'ai effectué une recherche à l'échelle de la solution pour ce qui précède, confirmé qu'il était présent dans tous mes projets Web et l'ai rapidement rejeté comme coupable. Finalement, il m'est venu à l'esprit de regarder ces résultats de recherche dans leur contexte complet:
<!-- For a description of web.config changes for .NET 4.5 see http://go.microsoft.com/fwlink/?LinkId=235367. The following attributes can be set on the <httpRuntime> tag. <system.Web> <httpRuntime targetFramework="4.5" /> </system.Web> -->
Doh.
Leçon: Si vous mettez à niveau un projet Web vers la version 4.5, vous devez toujours mettre ce paramètre en place manuellement.
la source
Votre test n'est pas défectueux et HttpContext.Current ne doit pas être nul après l'attente car dans l'API Web ASP.NET lorsque vous attendez, cela garantira que le code qui suit cette attente reçoit le HttpContext correct qui était présent avant l'attente.
la source
J'ai récemment rencontré ce problème. Comme Stephen l'a souligné, ne pas définir explicitement le cadre cible peut générer ce problème.
Dans mon cas, notre API Web a été migrée vers la version 4.6.2 mais le framework cible d'exécution n'a jamais été spécifié dans la configuration Web, donc fondamentalement, cela manquait dans la balise <system.web>:
Si vous avez des doutes sur la version du framework que vous exécutez, cela peut vous aider: Ajoutez la ligne suivante sur l'une de vos méthodes d'API Web et définissez un point d'arrêt pour vérifier le type actuellement chargé lors de l'exécution et vérifiez qu'il ne s'agit pas d'une implémentation héritée:
Vous devriez voir ceci (AspNetSynchronizationContext):
Au lieu de LegazyAspNetSynchronizationContext (ce que j'ai vu avant d'ajouter le framework cible):
Si vous accédez au code source ( https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs ), vous verrez que l'implémentation héritée de cette interface manque de prise en charge asynchrone.
J'ai passé beaucoup de temps à essayer de trouver la source du problème et la réponse de Stephen m'a beaucoup aidé. J'espère que cette réponse fournit plus d'informations sur le problème.
la source