2016-01-01 3 views
1

Je travaille avec .NET 3.5 avec un gestionnaire simple pour les requêtes http. À l'heure actuelle, à chaque requête http, mon gestionnaire ouvre une connexion tcp avec 3 serveurs distants afin de recevoir des informations de leur part. Ferme ensuite les sockets et écrit le statut du serveur sur Context.Response.Objet partagé entre différentes demandes

Cependant, je préférerais avoir un objet séparé qui se connecte toutes les 5 minutes aux serveurs distants via tcp, récupère les informations et les conserve. Donc, le HttpRequest, sur chaque requête serait beaucoup plus rapide en demandant simplement cet objet pour l'information. Donc mes questions ici sont, comment garder un objet global partagé en mémoire tout le temps qui peut aussi "réveiller" et faire ces connexions tcp même quand aucune demande http ne vient et rendre l'objet accessible au gestionnaire de requêtes http. .

+1

Vous pourriez avoir un service Windows en cours d'exécution pour cela, et écrire les données dans un fichier quelque part l'application ASP peut le lire. –

+0

qu'en est-il d'une demande arrivant juste quand le fichier est écrit? aussi, je ne suis pas sûr si c'est le meilleur moyen? –

+0

Puis attendez un peu jusqu'à ce que le fichier soit lisible. –

Répondre

0

Un service peut être exagéré pour cela.

Vous pouvez créer un objet global au démarrage de votre application et lui demander de créer un thread d'arrière-plan qui exécute la requête toutes les 5 minutes. Prenez la réponse (ou ce que vous traitez de la réponse) et placez-la dans une classe distincte, en créant une nouvelle instance de cette classe avec chaque réponse et utilisez System.Threading.Interlocked.Exchange pour remplacer une instance statique chaque fois que la réponse est extraite. Lorsque vous voulez regarder la réponse, copiez simplement une référence à l'instance statique vers une référence de pile et vous obtiendrez les données les plus récentes. Gardez à l'esprit, cependant, qu'ASP.NET supprimera votre application chaque fois qu'il n'y aura pas de demandes pendant un certain temps (temps d'inactivité), votre application s'arrêtera et redémarrera, provoquant la destruction de votre objet global et recréé.

Vous pouvez lire ailleurs que vous ne pouvez pas ou ne devez pas faire des tâches d'arrière-plan dans ASP.NET, mais ce n'est pas vrai - il vous suffit de comprendre les implications. J'ai le code semblable à l'exemple suivant travaillant sur un site ASP.NET qui gère plus de 1000 req/s de pointe (sur plusieurs serveurs).

Par exemple, dans Global.asax.cs:

public class BackgroundResult 
    { 
     public string Response; // for simplicity, just use a public field for this example--for a real implementation, public fields are probably bad 
    } 
    class BackgroundQuery 
    { 
     private BackgroundResult _result; // interlocked 
     private readonly Thread _thread; 

     public BackgroundQuery() 
     { 
      _thread = new Thread(new ThreadStart(BackgroundThread)); 
      _thread.IsBackground = true; // allow the application to shut down without errors even while this thread is still running 
      _thread.Name = "Background Query Thread"; 
      _thread.Start(); 

      // maybe you want to get the first result here immediately?? Otherwise, the first result may not be available for a bit 
     } 

     /// <summary> 
     /// Gets the latest result. Note that the result could change at any time, so do expect to reference this directly and get the same object back every time--for example, if you write code like: if (LatestResult.IsFoo) { LatestResult.Bar }, the object returned to check IsFoo could be different from the one used to get the Bar property. 
     /// </summary> 
     public BackgroundResult LatestResult { get { return _result; } } 

     private void BackgroundThread() 
     { 
      try 
      { 
       while (true) 
       { 
        try 
        { 
         HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://example.com/samplepath?query=query"); 
         request.Method = "GET"; 
         using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
         { 
          using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8)) 
          { 
           // get what I need here (just the entire contents as a string for this example) 
           string result = reader.ReadToEnd(); 
           // put it into the results 
           BackgroundResult backgroundResult = new BackgroundResult { Response = result }; 
           System.Threading.Interlocked.Exchange(ref _result, backgroundResult); 
          } 
         } 
        } 
        catch (Exception ex) 
        { 
         // the request failed--cath here and notify us somehow, but keep looping 
         System.Diagnostics.Trace.WriteLine("Exception doing background web request:" + ex.ToString()); 
        } 
        // wait for five minutes before we query again. Note that this is five minutes between the END of one request and the start of another--if you want 5 minutes between the START of each request, this will need to change a little. 
        System.Threading.Thread.Sleep(5 * 60 * 1000); 
       } 
      } 
      catch (Exception ex) 
      { 
       // we need to get notified of this error here somehow by logging it or something... 
       System.Diagnostics.Trace.WriteLine("Error in BackgroundQuery.BackgroundThread:" + ex.ToString()); 
      } 
     } 
    } 
    private static BackgroundQuery _BackgroundQuerier; // set only during application startup 

    protected void Application_Start(object sender, EventArgs e) 
    { 
     // other initialization here... 
     _BackgroundQuerier = new BackgroundQuery(); 
     // get the value here (it may or may not be set quite yet at this point) 
     BackgroundResult result = _BackgroundQuerier.LatestResult; 
     // other initialization here... 
    }