À L'Aide De HttpContext.Courant dans WebApi est dangereux en raison de async
Ma question est un peu lié à ce: WebApi équivalent pour HttpContext.Articles avec l'Injection de Dépendance.
Nous voulons injecter une classe à l'aide HttpContext.Courant dans WebApi zone à l'aide de Ninject.
Ma préoccupation est que ce pourrait être très dangereux, comme dans WebApi (tout?) est asynchrone.
S'il vous plaît corrigez-moi si je me trompe dans ces points, c'est ce que j'ai étudié jusqu'à présent:
-
HttpContext.Actuel devient le contexte actuel par Thread (j'ai regardé dans la mise en œuvre directement).
-
À L'Aide De HttpContext.Courant à l'intérieur de async Tâche n'est pas possible, car il peut fonctionner sur un autre Thread.
-
WebApi utilise IHttpController avec la méthode
Task<HttpResponseMessage> ExecuteAsync
=> chaque demande est async => vous ne pouvez pas utiliser HttpContext.Courant à l'intérieur de la méthode d'action. Il pourrait même arriver, plus de requêtes sont exécutées sur le même thread par coicidence. -
Pour la création de contrôleurs injectées avec des trucs dans les constructeurs IHttpControllerActivator est utilisé avec sync méthode
IHttpController Create
. C'est, où ninject crée Contrôleur avec toutes ses dépendances.
-
Si je suis correct dans l'ensemble de ces 4 points, à l'aide de HttpContext.Courant à l'intérieur d'une méthode d'action ou de toute couche ci-dessous est très dangereux et peut avoir des résultats inattendus. J'ai vu sur de SORTE que beaucoup de réponses acceptées ce qui suggère exactement cela. À mon humble avis, cela peut fonctionner pendant un certain temps, mais il ne pourra pas sous la charge.
-
Mais lors de l'utilisation de DI de créer un Contrôleur et de ses dépendances, c'est Ok, parce que cela fonctionne sur un thread séparé. J'ai pu obtenir une valeur de la HttpContext dans le constructeur et il serait à l'abri?. Je me demande si chaque Contrôleur est créé sur un seul thread pour chaque demande, car cela pourrait provoquer un problème de sous de lourdes charges, où tous les threads de IIS peut être consommé.
Juste pour expliquer pourquoi je veux injecter HttpContext trucs:
- une solution serait de faire la demande dans la méthode d'action de contrôleur et passer à la valeur nécessaire tous les calques en tant que param jusqu'à ce que son utilisé quelque part profondément dans le code.
-
notre voulaient solution: toutes les couches entre ne sont pas afected par cela, et nous pouvons utiliser l'injection de demande de quelque part profondément dans le code (par exemple, dans certains ConfigurationProvider qui dépend de l'URL)
Merci de me donner votre avis si je suis totalement tort ou mes suggestions sont corrects, ce thème semble être très compliqué. Merci à l'avance!
- C'est une question très intéressante. Cependant, autant que je sache, si le code ne prévoit pas explicitement de reporter les travaux à un autre thread, les choses seront toujours exécutées sur le même thread. Cela est également vrai pour les tâches asynchrones. Bien que ce ne sera pas bloquer le thread appelant, ça va encore être exécuté sur le thread appelant. Mais je ne suis pas sûr à 100%.. vous devriez l'essayer 😉
- c'est exactement le problème avec vous attendent pour la plupart rester sur le même fil, mais vous ne pouvez pas être sûr à ce sujet. c'est pourquoi l'OMI tout le monde pense que cela fonctionne, mais va rompre dans des circonstances.. À la Tâche.Courir, c'est bien, c'est un autre thread.
- pourquoi pensez-vous que vous ne pouvez pas être sûr à ce sujet? Plus que avec une "synchronisation" de la méthode? La méthode de synchronisation peut également exécuter
Task.Run(..)
ou il pourrait générer un nouveau thread et dans ce thread essayer d'obtenir le HttpContext injecté.. etc. Alors, quelle est la différence? - Lorsque vous ne
Task.Run
, vous le faites par vous-même et vous savez à quoi s'attendre, c'est ok pour moi. Ma préoccupation est,comme la méthode d'action dans webapi est exécutée de manière asynchrone par le cadre, c'est toujours être considéré comme asynchrone avec tous ses pièges. Je pense que, il est même possible, deux Demandes d'exécuter sur le même thread (c'est le but de l'attendent/async je pense) => HttpContext.Courant sera de retour une fausse valeur. En fait, cette question a déjà frappé moi une fois, par la prise de conscience que log4net LogicalThreadContext.Les propriétés ne sont pas de travail en vous connectant WebApi, mais en MVC ils font un travail. - Pour answere votre question, pourquoi voudrais-je pense qu'il n'est pas sûr qu'il est en cours d'exécution sur le même fil? - J'ai lu beaucoup d'articles sur internet et il semble que la communauté n'est pas vraiment sûr de cela, mais j'ai eu le sentiment que le SyncronizationContext va décider de commencer à nouveau Thread, ou non, selon les circonstances actuelles, mais practicaly cette situation est très rare. (pas encore sûr à 100% sur ce que beaucoup d'opinions différentes sur internet)
Vous devez vous connecter pour publier un commentaire.
Il serait plus correct de dire que
HttpContext
est appliqué à un fil, ou d'un fil "entre" laHttpContext
.Pas du tout; le comportement par défaut de
async
/await
reprendra sur l'arbitraire d'un fil, mais ce thread va entrer dans le contexte de la demande avant de reprendre votreasync
méthode.La clé, c'est la
SynchronizationContext
. J'ai un MSDN article sur le sujet si vous n'êtes pas familier avec elle. UnSynchronizationContext
définit un "contexte" pour une plate-forme avec la commune étant de l'INTERFACE utilisateur contextes (WPF, WinPhone, WinForms, etc), le pool de threads contexte, et la ASP.NET contexte de demande.L'ASP.NET contexte de demande gère
HttpContext.Current
ainsi que quelques autres choses comme la culture et de sécurité. L'INTERFACE utilisateur, les contextes sont tous étroitement associée à un seul thread (la thread d'INTERFACE utilisateur), mais le ASP.NET contexte de demande n'est pas liée à un thread spécifique. Il sera, cependant, ne permettre qu'à un fil dans le contexte de la demande à un moment.L'autre partie de la solution est comment
async
etawait
travail. J'ai unasync
intro sur mon blog qui décrit leur comportement. En résumé,await
par défaut permettra de saisir le contexte actuel (qui estSynchronizationContext.Current
, sauf si elle estnull
), et d'utiliser ce contexte pour reprendre leasync
méthode. Donc,await
est capture automatiquement la ASP.NETSynchronizationContext
et reprendre leasync
méthode dans ce contexte de demande (et donc de la préservation de la culture, de la sécurité, etHttpContext.Current
).Si vous
await
ConfigureAwait(false)
, alors vous êtes explicitement direawait
à pas de capture du contexte.Noter que ASP.NET ne changer son
SynchronizationContext
de travailler proprement avecasync
/await
. Vous devez vous assurer que l'application est compilée en contre .NET 4.5 et aussi explicitement des objectifs de 4,5 dans son site web.config; c'est la valeur par défaut pour les nouveaux ASP.NET 4.5 projets mais doit être explicitement défini si vous avez mis à niveau à partir d'un projet existant ASP.NET 4.0 ou version antérieure.Vous pouvez vous assurer que ces paramètres sont corrects par l'exécution de votre application contre .NET 4.5 et en observant
SynchronizationContext.Current
. Si c'estAspNetSynchronizationContext
, alors vous êtes bon; si c'estLegacyAspNetSynchronizationContext
, les réglages sont mauvais.Aussi longtemps que les paramètres sont corrects (et que vous utilisez le ASP.NET 4.5
AspNetSynchronizationContext
), alors vous pouvez utiliser en toute sécuritéHttpContext.Current
après uneawait
sans vous en soucier.httpRuntime
à4.5
. Dès que je l'ai fait, tous mes problèmes ont disparus.ConfigureAwait(false)
, ce qui est explicitement dire ASP.NET qu'il ne pas besoin de la requête HTTP contexte, et alors qu'il accède à la requête HTTP contexte. Donc oui, je m'attends à une panne. La solution idéale est d'utiliserawait
au lieu deTask.Wait
.await
au lieu deTask.Wait
.AsyncLocal<T>
; si vous avez correctement cible .NET 4.5 ou supérieur,HttpContext.Current
coule à traversawait
points.AsyncLocal
wrapper et de ton commentaire surHttpContext.Current
qui coule à traversawaits
- il ne semble pas être le cas dans WCF. Signifie-t-il la solution peut encore être utilisé?SynchronizationContext
, il ne laisse que jusqu'à son hôte). Mais vous pouvez utiliserAsyncLocal
(dans une .NET 4.5 ou version plus récente de l'exécution), peu importe.await
s. Malheureusement, même l'approche proposée impliquantAsyncLocal
ne semble pas aider (ou au moins, nous avons quelques problèmes à l'utiliser). C'est vraiment la honte de la WCF ne rentre pas dans le modèle asynchrone en tant que bien que d'autres sous-systèmes ne. Ma question a été posée essentiellement pour s'assurer de la WCF n'a tout simplement pas suivre.async
est sorti quand WebAPI était en train de devenir à la mode, de sorte WCF ne se perdent un peu. Une chose à vérifier est lehttpRuntime@targetFramework
paramètre dans votreweb.config
; autre que cela, vous êtes probablement mieux de l'ouverture d'un MS problème de prise en charge.Je suis en utilisant une api web, qui est à l'aide de async/await méthodologie.
également à l'aide de
C'était très bien pour une bonne quantité de temps qui a éclaté subitement pour pas de changement de code.
Passer beaucoup de temps en revenir à la précédente versions anciennes, trouvé la clé manquante à l'origine du problème.
Je ne suis pas un expert sur le plan technique. Mais je suggère d'ajouter la clé de votre configuration web et de lui donner un ALLER.
J'ai trouvé très bon article qui décrit exactement ce problème: http://byterot.blogspot.cz/2012/04/aspnet-web-api-series-part-3-async-deep.html?m=1
auteur étudié profondément, comment le ExecuteAsync méthode est appelée dans le WebApi cadre et est venu à cette conclusion:
ASP.NET Web API actions (et tous le pipeline méthodes) va être appelée de façon asynchrone uniquement si vous retournez une Tâche ou une Tâche<T>. Cela peut paraître évident, mais aucun de la canalisation méthodes avec Async suffixe s'exécutent dans leur propre fils. À l'aide de couverture Async pourrait être un abus de langage. [Mise à JOUR: ASP.NET de l'équipe ont en effet confirmé que l'Asynchrone est utilisé pour indiquer les méthodes qui retournent des Tâches et vous pouvez exécuter de manière asynchrone, mais n'ont pas d']
Ce que j'ai compris de l'article, c'est que les méthodes d'Action sont appelés de façon synchrone, mais c'est à l'appelant de la décision.
J'ai créé une petite application de test à cette fin, quelque chose comme ceci:
et une version Asynchrone de retour
async Task<object>
J'ai essayé de faire un peu d'attaque DOS sur elle avec jquery et n'a pas pu déterminer toute question jusqu'à ce que j'ai utilisé
await Task.Delay(1).ConfigureAwait(false);
, ce qui est évident qu'il serait un échec.Ce que j'ai pris à partir de l'article, c'est que le problème est très compliqué et le Fil de l'interrupteur peut se produire lors de l'utilisation de méthode d'action asynchrone, donc c'est vraiment un PAS une bonne idée d'utiliser HttpContext.Actuelle de n'importe où dans le code de l'action des méthodes. Mais comme le contrôleur est créé de manière synchrone, à l'aide de HttpContext.Courant dans le constructeur ainsi que dans l'injection de dépendance est OK.
Quand quelqu'un a une autre explication à ce problème s'il vous plaît corrigez-moi que ce problème est très compliqué d'une je ne suis pas encore convaincu à 100%.
diclaimer: