IHttpHandler可以重用,但它没有被重用。

5

我有一个IHttpHandler,我相信它可以受益于重用,因为它的设置很昂贵,而且是线程安全的。但是每个请求都会创建一个新的处理程序。我的处理程序没有被重用。

以下是我的简单测试用例,没有昂贵的设置。这个简单的案例展示了我的问题:

public class MyRequestHandler : IHttpHandler
{
    int nRequestsProcessed = 0;

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        nRequestsProcessed += 1;
        Debug.WriteLine("Requests processed by this handler: " + nRequestsProcessed);
        context.Response.ContentType = "text/plain";
        context.Response.Write("Hello World");
    }
}

Requests processed by this handler: 1
Requests processed by this handler: 1
Requests processed by this handler: 1
Requests processed by this handler: 1... at least 100 times. I never see > 1.

我是否误解了IsReusable的工作原理?是否还有其他可以阻止重用的因素?如果我的处理程序是从Silverlight应用程序调用的,那么会有什么不同吗?


你是如何将处理程序附加到应用程序的?通过 web.config 还是编程方式? - Jacob
这是我的第一个应用程序。我在Visual Studio中创建了一个新的ASP.NET网站项目。为了运行服务器,我正在从Visual Studio中运行调试。 - Mark Schmucker
我想问一下你是如何配置MyRequestHandler的运行方式的。例如,它是在你的web.config中进行配置的,还是你在Global.asax中编写了注册代码? - Jacob
哦,我不是很清楚。在web.config或global.asax中都没有提到MyRequestHandler。当我运行Visual Studio调试器时,它会启动一个服务器,然后我的Silverlight应用程序使用表单“http://localhost:51532/MyRequestHandler.ashx?level=13&x=19&y=5&width=256&height=256”请求图像瓦片。顺便说一下,该项目基于Jeff Prosise的《动态深度缩放》文章(http://msdn.microsoft.com/en-us/magazine/dd943052.aspx)。 - Mark Schmucker
如果那是一些由Visual Studio提供的调试服务器,那可能解释了为什么它不会尝试在自身中重复使用。 - Jon Hanna
这是非常可能的。最终我选择了usr的解决方案,所以我的原始问题并不重要。 - Mark Schmucker
2个回答

3

IsReusable并不是一个保证。

只需重构您的处理程序并将所有跨请求状态放入不同的类中。在Web应用程序中清楚地分离跨请求状态是最佳实践,因为这很危险。


我的昂贵设置涉及分配高达100 MB的内存,假设它不能被设计得更好,因此分配是不可避免的。我不想为每个请求重新分配100 MB。我可以使用什么“不同类”来持久化该内存指针,以便多个请求(或多个处理程序)可以访问它? - Mark Schmucker
只需使用指向状态保持类实例的静态变量。或将其放入http应用程序字典中。任何类型的静态存储都可以(顺便确保线程安全)。 - usr

1

如果它是线程安全的,那么您可以比重用更好。

IsReusable返回true时:

  1. 首先创建处理程序的实例。
  2. 调用它的ProcessRequest
  3. 它可能被放入池中以便再次使用。

这意味着它可以减少重复的设置成本,但不一定(没有保证)并且不完全 - 如果同一个URI有多个并发调用,则需要创建几个这样的处理程序来同时处理它们。

这种方法的好处是(当发生池化时),处理程序实际上不必是线程安全的。

由于您的确实是线程安全的,我们可以通过以下两种方式之一做得更好。

一种方法是将所有功能都放入另一个类中。然后,处理程序可以只是一个瘦小的类,其中ProcessRequest通过静态实例传递给该类。

同样,我们可以使用IHttpHandlerFactory来处理您当前的类:

public class MyRequestHandlerFactory : IHttpHandlerFactory
{
  private static MyRequestHandler SingletonHandler = new MyRequestHandler();
  IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
  {
    return SingletonHandler;
  }
  void ReleaseHandler(IHttpHandler handler)
  {
    //do nothing
  }
}

通过上述类,您只需更改Web.Config以引用MyRequestHandlerFactory,而不是当前引用MyRequestHandler,它将完美地工作。
(除非您实际上并不像您想象的那样线程安全,否则-糟糕!)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接