2009-12-23 8 views
0

J'écris un processeur de file d'attente ASP.NET. Les utilisateurs vont se connecter et télécharger des fichiers de données sur le site, puis cliquer pour commencer le traitement des fichiers de données.Passage des chaînes au service Windows .NET

J'ai un service Windows sur le système qui attend que les éléments arrivent dans la file d'attente et les traite. Jusqu'à présent, tout fonctionne sauf que les éléments de la file d'attente semblent se perdre. Je crois que les membres statiques perdent de la portée, mais je ne suis pas sûr de savoir comment y remédier. J'ai pensé à écrire des choses de/à partir de fichiers, mais les mises à jour d'état si souvent ce serait un tueur de performance.

Quelle est la meilleure façon d'obtenir et de retirer des données du service?

Le service Windows est la suivante:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.ServiceProcess; 
using System.Threading; 
using System.Timers; 

namespace MyMonitorService 
{ 
    public class MyMonitor : ServiceBase 
    { 
     #region Members 
     private System.Timers.Timer timer = new System.Timers.Timer(); 
     private static Queue<String> qProjectQueue = new Queue<String>(); 
     private static Mutex mutexProjectQueue = new Mutex(false); 
     private Boolean bNotDoneYet = false; 
     #endregion 

     #region Properties 
     public static String Status { get; private set; } 
     #endregion 

     #region Construction 
     public MyMonitor() 
     { 
      this.timer.Interval = 10000; // set for 10 seconds 
      this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed); 

      Status = String.Empty; 
     } 
     #endregion 

     private void timer_Elapsed (object sender, ElapsedEventArgs e) 
     { 
      try 
      { 
       if (!this.bNotDoneYet) 
       { 
        this.bNotDoneYet = true; 
        for (;;) 
        { 
         MyMonitor.mutexProjectQueue.WaitOne(); 
         if (MyMonitor.qProjectQueue.Count == 0) 
         { 
          EventLog.WriteEntry("MyMonitor", "The queue is empty", EventLogEntryType.Information); 
          break; 
         } 
         String strProject = MyMonitor.qProjectQueue.Dequeue(); 
         EventLog.WriteEntry("MyMonitor", String.Format("The project {0} was dequeued", strProject), EventLogEntryType.Information); 
         MyMonitor.mutexProjectQueue.ReleaseMutex(); 

         // Do something that updates MyMonitor.Status up to thousands of times per minute 
        } 
       } 
       this.bNotDoneYet = false; 
      } 
      catch (Exception ex) 
      { 
       EventLog.WriteEntry("MyMonitor", ex.Message, EventLogEntryType.Error); 
      } 
     } 

     public static void EnqueueProjects (params String[] astrProjects) 
     { 
      try 
      { 
       String strMessage = String.Format("The following projects were added to the queue:\n{0}", String.Join("\n", astrProjects)); 
       EventLog.WriteEntry("MyMonitor", strMessage, EventLogEntryType.Information); 

       if (astrProjects == null) 
        return; 

       MyMonitor.mutexProjectQueue.WaitOne(); 

       foreach (String strProject in astrProjects) 
        MyMonitor.qProjectQueue.Enqueue(strProject); 

       MyMonitor.mutexProjectQueue.ReleaseMutex(); 
      } 
      catch (Exception e) 
      { 
       EventLog.WriteEntry("MyMonitor", e.Message, EventLogEntryType.Error); 
      } 
     } 

     #region Service Start/Stop 
     [STAThread] 
     public static void Main() 
     { 
      ServiceBase.Run(new MyMonitor()); 
     } 

     protected override void OnStart (string[] args) 
     { 
      try 
      { 
       EventLog.WriteEntry("MyMonitor", "MyMonitor Service Started", EventLogEntryType.Information); 
       this.timer.Enabled = true; 
      } 
      catch (Exception e) 
      { 
       EventLog.WriteEntry("MyMonitor", e.Message, EventLogEntryType.Error); 
      } 
     } 

     protected override void OnStop() 
     { 
      try 
      { 
       EventLog.WriteEntry("MyMonitor", "MyMonitor Service Stopped", EventLogEntryType.Information); 
       this.timer.Enabled = false; 
      } 
      catch (Exception e) 
      { 
       EventLog.WriteEntry("MyMonitor", e.Message, EventLogEntryType.Error); 
      } 
     } 
     #endregion 
    } 
} 

Répondre

1

Répondant à la question générale comment cela pourrait être résolu (encore incertain au sujet du code à la main):

en fonction de vos besoins. De "facile" à "haut de gamme":

  • entrées du système de fichiers (avec veilleur ou vote)
  • messages Windows, SendMessage/PostMessage
  • Une couche de base de données partagée
  • Queues Message (MS MQ par exemple)

En ce qui concerne votre code:

première pensée qui traverse l'esprit: Si la file d'attente se trouve être o vide nce vous allez sortir de l'événement timer et le bNotDoneYet n'est jamais réinitialisé à false -> Les nouvelles entrées ne seront pas prises en compte?

En outre votre modèle de producteur/consommateur semble off pour moi. Je suis habitué à un poids léger (et simplifié):

Producteur:

lock (_syncRoot) { 
    _queue.Enqueue(obj); 
    if (_queue.Count == 1) Monitor.Pulse(_syncRoot); 
} 

Consommateur:

lock (_syncRoot) { 
    while (_queue.Count < 1) { 
    try { 
     Monitor.Wait(_syncRoot); 
    } catch (ThreadInterruptedException) {} 
    } 
    var obj = _queue.Dequeue(); 
} 
+0

pourrait héberger un service WCF dans le service Windows, et ont le ASP.NET app appelez ce service. (Une variante plus structurée sur votre suggestion MSMQ.) – itowlson

+0

Désolé pour le bNotDoneYet = false étant manquant; Je l'ai manqué dans la 'désinfection' du code. Aussi, merci pour les échantillons de synchronisation. Je ne fais pas beaucoup ces jours-ci en synchronisation. –

+0

@itowlson: Bon point, raté ça. –

Questions connexes