不同请求之间的共享对象

时间:2016-01-01 19:38:40

标签: c# .net asp.net-3.5

我正在使用.NET 3.5和一个简单的http请求处理程序。现在,在每个http请求上,我的处理程序打开与3个远程服务器的tcp连接,以便从它们接收一些信息。然后关闭套接字并将服务器状态写回Context.Response。

但是,我希望有一个单独的对象,每隔5分钟通过tcp连接到远程服务器,获取信息并保留它。因此,HttpRequest,在每个请求上只需要询问此对象的信息就会快得多。

所以我的问题是,如何将共享的全局对象一直保留在内存中,即使没有http请求即可“唤醒”这些tcp连接,并且可以访问http请求处理程序。

1 个答案:

答案 0 :(得分:0)

此服务可能过度。

您可以在应用程序启动时创建一个全局对象,并让它创建一个后台线程,每隔5分钟执行一次查询。获取响应(或者您从响应中处理的内容)并将其放入单独的类中,使用每个响应创建该类的新实例,并在每次检索响应时使用System.Threading.Interlocked.Exchange替换静态实例。如果要查看响应,只需将静态实例的引用复制到堆栈引用,即可获得最新数据。

但请记住,只要没有请求一段时间(空闲时间),ASP.NET就会终止您的应用程序,因此您的应用程序将停止并重新启动,从而导致您的全局对象被销毁并重新创建

你可能会在其他地方读到你不能或不应该在ASP.NET中做背景的事情,但事实并非如此 - 你只需要了解它的含义。我有以下示例的代码,类似于处理超过1000 req / sec峰值(跨多个服务器)的ASP.NET站点。

例如,在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...
    }