2016-01-01 17 views
1

Я работаю с .NET 3.5 с простым обработчиком для HTTP-запросов. Прямо сейчас, при каждом HTTP-запросе мой обработчик открывает tcp-соединение с тремя удаленными серверами, чтобы получить от них некоторую информацию. Затем закрывает сокеты и записывает статус сервера обратно в Context.Response.Общий объект среди разных запросов

Однако, я бы предпочел иметь отдельный объект, который каждые 5 минут соединяется с удаленными серверами через tcp, получает информацию и сохраняет ее. Таким образом, HttpRequest по каждому запросу будет намного быстрее, просто задав этот объект для информации.

Итак, мои вопросы касательно того, как поддерживать общий глобальный объект в памяти все время, которое также может «просыпаться» для тех подключений tcp даже при отсутствии запросов HTTP и иметь объект, доступный для обработчика запросов HTTP ,

+1

Вы могли бы иметь службу Windows работает для этого, и записывать данные в файл где-то приложение ASP может прочитать его. –

+0

Как насчет запроса, поступающего прямо при записи файла? Кроме того, я не уверен, что это лучший способ? –

+0

Затем подождите немного, пока файл не станет читаемым. –

ответ

0

Услуга может быть излишней для этого.

Вы можете создать глобальный объект в начале приложения и создать фоновый поток, который выполняет запрос каждые 5 минут. Возьмите ответ (или то, что вы обрабатываете из ответа), и поместите его в отдельный класс, создав новый экземпляр этого класса с каждым ответом и используйте System.Threading.Interlocked.Exchange, чтобы заменить статический экземпляр каждый раз при получении ответа. Когда вы хотите посмотреть ответ, просто скопируйте ссылку на статический экземпляр в ссылку на стек, и у вас будут самые последние данные.

Помните, однако, что ASP.NET будет убивать ваше приложение, когда не будет запросов на определенное количество времени (простой), поэтому ваше приложение остановится и перезапустится, в результате чего ваш глобальный объект будет уничтожен и воссоздан.

Вы можете прочитать в другом месте, что вы не можете или не должны делать фоновый материал в ASP.NET, но это неправда - вам просто нужно понять последствия. У меня есть аналогичный код для следующего примера, работающего на сайте ASP.NET, который обрабатывает более 1000 req/sec пиков (на нескольких серверах).

Например, в 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... 
    }