Exécution d’une opération asynchrone déclenchée par une requête de page Web ASP.NET

J’ai une opération asynchrone qui, pour diverses raisons, doit être déclenchée à l’aide d’un appel HTTP vers une page Web ASP.NET. Lorsque ma page est demandée, elle doit démarrer cette opération et retourner immédiatement un accusé de réception au client.

Cette méthode est également exposée via un service Web WCF et fonctionne parfaitement.

Lors de ma première tentative, une exception m’a été lancée en me disant:

  Les opérations asynchrones ne sont pas autorisées dans ce contexte.
 La page commençant une opération asynchrone doit avoir l'Async
 atsortingbut défini sur true et une opération asynchrone ne peut être que
 démarré sur une page avant l'événement PreRenderComplete. 

Donc, bien sûr, j’ai ajouté le paramètre Async="true" à la directive @Page . Maintenant, je ne reçois pas d’erreur, mais la page est bloquée jusqu’à la fin de l’opération asynchrone.

Comment puis-je obtenir une vraie page “feu-et-oublier”?

Modifier: du code pour plus d’informations. C’est un peu plus compliqué que ça, mais j’ai essayé de comprendre l’idée générale.

 public partial class SendMessagePage : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { ssortingng message = Request.QuerySsortingng["Message"]; ssortingng clientId = Request.QuerySsortingng["ClientId"]; AsyncMessageSender sender = new AsyncMessageSender(clientId, message); sender.Start(); Response.Write("Success"); } } 

La classe AsyncMessageSender:

 public class AsyncMessageSender { private BackgroundWorker backgroundWorker; private ssortingng client; private ssortingng msg; public AsyncMessageSender(ssortingng clientId, ssortingng message) { this.client = clientId; this.msg = message; // setup background thread to listen backgroundThread = new BackgroundWorker(); backgroundThread.WorkerSupportsCancellation = true; backgroundThread.DoWork += new DoWorkEventHandler(backgroundThread_DoWork); } public void Start() { backgroundThread.RunWorkerAsync(); } ... // after that it's pretty predictable } 

Si vous ne vous souciez pas de retourner quoi que ce soit à l’utilisateur, vous pouvez simplement lancer un thread séparé ou, pour une approche rapide et sale, utiliser un délégué et l’appeler de manière asynchrone. Si vous ne vous souciez pas d’avertir l’utilisateur lorsque la tâche asynchrone se termine, vous pouvez ignorer le rappel. Essayez de placer un point d’arrêt à la fin de la méthode SomeVeryLongAction () et vous verrez qu’il se termine lorsque la page a déjà été servie:

 private delegate void DoStuff(); //delegate for the action protected void Page_Load(object sender, EventArgs e) { } protected void Button1_Click(object sender, EventArgs e) { //create the delegate DoStuff myAction = new DoStuff(SomeVeryLongAction); //invoke it asynchrnously, control passes to next statement myAction.BeginInvoke(null, null); Button1.Text = DateTime.Now.ToSsortingng(); } private void SomeVeryLongAction() { for (int i = 0; i < 100; i++) { //simulation of some VERY long job System.Threading.Thread.Sleep(100); } } 

OK, voici le problème: l’atsortingbut Async est pour le cas où votre page va appeler une tâche longue qui bloque également le thread, puis votre page a besoin du résultat de cette tâche pour renvoyer des informations à l’utilisateur. Par exemple, si votre page doit appeler un service Web, attendez sa réponse, puis utilisez les données de la réponse pour rendre votre page.

La raison pour laquelle vous utiliseriez l’atsortingbut Async est d’éviter de bloquer le thread. Cela est important car les applications ASP.NET utilisent un pool de threads pour traiter les demandes et le nombre de threads disponibles est relativement faible. Et si chaque appel lie le thread en attendant l’appel du service Web, vous allez bientôt atteindre un nombre suffisant d’utilisateurs simultanés que les utilisateurs devront attendre jusqu’à la fin de ces appels de service Web. L’atsortingbut Async permet au thread de revenir au pool de threads et de servir d’autres visiteurs simultanés sur votre site Web, plutôt que de le forcer à restr assis à ne rien faire en attendant le retour de l’appel du service Web.

Le résultat pour vous est le suivant: l’atsortingbut Async est conçu pour le cas où vous ne pouvez pas afficher la page tant que la tâche asynchrone n’est pas terminée, et c’est pourquoi elle ne rend pas la page immédiatement.

Vous devez lancer votre propre thread et en faire un thread de démon. Je ne me souviens pas de la syntaxe exacte pour cela, mais vous pouvez facilement la trouver dans le document en recherchant le document “daemon” dans le document BCL. Cela signifie que le thread empêchera votre application de s’arrêter en cours de vie, ce qui est important car ASP.NET et IIS se réservent le droit de “recycler votre processus” lorsqu’ils le jugent nécessaire, et si cela se produit pendant que votre thread fonctionne, votre tâche sera stoppée. Faire en sorte que le démon de thread empêche cela (sauf pour certains cas de bord rares possibles, vous en saurez plus lorsque vous trouverez la documentation à ce sujet).

Ce thread démon est l’endroit où vous lancerez ces tâches. Et après avoir dit au thread du démon de faire la tâche, vous pouvez immédiatement rendre votre page … afin que le rendu de la page se fasse immédiatement.

Mieux qu’un thread de démon dans votre processus ASP.NET, il serait préférable d’implémenter un service Windows pour effectuer cette tâche. Demandez à votre application ASP.NET de communiquer la tâche à exécuter au service. Pas besoin d’un thread de démon et pas besoin de s’inquiéter du recyclage de votre processus ASP.NET. Comment dites-vous au Service de faire la tâche? Peut-être via WCF, ou peut-être en insérant un enregistrement dans une table de firebase database interrogée par le Service. Ou un certain nombre d’autres façons.

EDIT: Voici une autre idée que j’ai déjà utilisée dans ce même but. Ecrivez les informations sur votre tâche dans une queue MSMQ. Demandez à un autre processus (peut-être même sur une autre machine) de sortir de cette queue et d’effectuer la tâche fastidieuse. Le travail d’insertion dans une queue est optimisé pour revenir le plus rapidement possible, afin que votre thread ne soit pas bloqué pendant que les données que vous mettez dans la queue sont envoyées via le câble ou quelque chose du genre. C’est l’un des moyens les plus rapides de noter qu’une tâche doit être effectuée sans attendre l’exécution de cette tâche.

Si vous exécutez webforms, définissez Ansync = “true” dans votre page .aspx où vous effectuez la requête.
<%@ Page Language="C#" Async="true" ... %>

Vous pouvez contourner cette limitation assez facilement et sans même définir Async sur true.

 public void Start() { new Task(() => { backgroundThread.RunWorkerAsync(); }).Start(); } 

Si vous obtenez cette erreur lorsque vous appelez le service Web de manière asynchrone, veillez à append l’atsortingbut Async = ‘true’ conformément aux instructions du message d’exception?

haut de la page