À l'aide de HttpContext dans Async Task
J'ai le texte suivant 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.
}
}
Dans le groupe de la HttpContext obtient la valeur null. Nous avons fait beaucoup de ruse, mais rien ne nous assure de la HttpContext être toujours disponible dans notre nouveau thread.
Est-il une solution pour utiliser HttpContext au sein de sortir async tâches?
Dans notre IocContainer nous avons enregistré l'objet suivant qui passe le nom d'utilisateur pour le cadre.
public class HttpContextUserIdentityName : ICredentials
{
public string Name
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
Ce code est appelé dans beaucoup d'autres endroits avant de la persistance de la base de données.
Nous avons besoin d'une autre façon d'obtenir le nom d'utilisateur de l'utilisateur qui a initié la webrequest ou de corriger le problème avec le HttpContext être null.
En raison de la persistance de la base de données qui se passe dans la Tâche que je ne peux pas accéder à la HttpContext avant d'entrer dans la tâche.
Je ne peux pas penser à un moyen sûr de temporaire de conserver le nom d'utilisateur afin que je puisse mettre en œuvre un autre ICredentials objet de service.
OriginalL'auteur Marco Franssen | 2012-12-06
Vous devez vous connecter pour publier un commentaire.
Vous presque ne voulez pas utiliser
Task.Run
dans un ASP.NET méthode.Je pense que la solution la plus propre (mais la plupart des travaux) est de mettre en œuvre
async
les interfaces compatibles à vos autres couches:OriginalL'auteur Stephen Cleary
Je voudrais essayer de passer dans la référence à la HttpContext que l'état de l'objet, parce que cela devrait créer une nouvelle instance de l'objet sur la pile du thread qui exécute le travail. Au lieu d'utiliser de la Tâche.Exécuter, utiliser
Tâche.Exécuter et de la Tâche.Usine.StartNew retourner immédiatement, de sorte asp.net continue dans le cas du cycle de vie dans le thread de travail est en charge de la demande, tandis que votre fil est en fonctionnement sur l'objet qui a déjà été éliminés.
HttpContext
n'est pas unstruct
. Ensuite, il y a une raison, il n'est pas accessible à partir d'un thread d'arrière-plan, et que la raison est qu'il n'a pas été conçu pour être accessible à partir d'autres contextes. Ce n'est pas un "thread-safe" de l'objet par sa conception, vous ne pouvez compter que sur l'état actuel de l'objet lorsque vous êtes dans la synchronisation approprié contexte, etc. Vous êtes tout simplement pas censés pour accéder à laHttpContext
partir d'un autre thread, juste la manière que dans une application winform vous n'avez pas de contrôles d'accès à partir d'un non-thread d'INTERFACE utilisateur.Selon cette question et de la réponse, vous pouvez fermer sur le HttpContext. Si chaque thread obtient sa propre pile et de la HttpContext est passé à ce thread comme paramètre, puis une copie de cet objet doit obtenir créé sur le tas pour le nouveau thread.
Assurez-vous de close sur elle. Je n'ai jamais dit que vous ne pouvais pas j'ai dit que vous ne pas. Oui, chaque thread arrive c'est le propre de la pile, je ne suis pas certain que. Ce que je suis disputant est que ce que vous faites est en quelque sorte la copie du contexte; il ne l'est pas. Alors que les piles sont différentes (par nécessité) le segment est partagé. Depuis
HttpContext
est un type de référence, l'objet réel est assis sur le tas. Vous êtes la seule copie une référence à cet objet dans votre fermeture.Ok, cela peut ne pas être la réponse à la question ci-dessus, mais il a été utile pour moi, merci! 🙂
OriginalL'auteur pwnyexpress
Vous devriez obtenir toutes les informations que vous avez besoin dans le contexte actuel avant de commencer le nouveau thread. Dans ce cas, ajouter quelque chose comme:
avant
Task.Run
et ensuite l'utiliser à l'intérieur de l'autre thread.Sur une note de côté, comme il est, il n'y a pas de raison de
await
la tâche. Il suffit de vous rendre la tâche directement, et non pas la marque de la méthode commeAsync
.Si vous avez besoin d'accéder à la
Response
objet, qui sera sans doute d'utiliser les résultats de l'opération longue à exécuter et ne peut donc pas être avantTask.Run
vous devriez le faire après laTask.Run
(mais de s'assurer que la tâche estawait
ed). Si vous finissez par faire cela, alors vous ne pouvez pas faire ce que j'ai suggéré dans mon précédent paragraphe.Vous ne serez pas en mesure d'accéder le contexte actuel, à partir d'un thread d'arrière-plan, c'est juste ne va pas arriver. Comme je l'ai déjà dit, vous avez besoin pour obtenir de l'information à partir du contexte actuel avant de démarrer le thread d'arrière-plan. L'autre problème, peut-être que vous faites plus que vous devriez être en tâche de fond. Peut-être des sections de cette méthode doit être refait entièrement à exécuter ailleurs, ou seulement une petite section qui interagit avec la DB ou fait du traitement doit être configuré pour s'exécuter en tâche de fond. Le problème ici est de mélanger les affaires et le code de l'INTERFACE utilisateur.
Vous pouvez réellement fermer sur le HttpContext objet que l'objet de l'état pour une nouvelle tâche. Cela devrait créer une nouvelle copie de cet objet sur la pile pour le nouveau thread. Voir la réponse ci-dessous.
J'ai fait la liste de plusieurs des problèmes que dans un commentaire à votre fil; cela mis à part, vous n'êtes pas en train de clôture dans votre code, vous êtes juste en passant comme paramètre formel. C'est...différent.
OriginalL'auteur Servy