4

我有一些简单的类需要在请求结束时进行处理。

为此,我Dispose从.Application_EndRequestGlobal.asax

这“在我的机器上运行良好”但在我得到的生产服务器上导致了一些问题Cannot access a disposed object.这发生在一些 MVC 帮助程序中。

在我看来,Application_EndRequest 是在请求​​结束时触发的。不是这样吗?我应该使用另一个事件来处理我的对象吗?

4

3 回答 3

5

应用程序池问题 - 可能

我怀疑您的一次性对象不一定是请求,而是应用程序范围(它可能会根据请求实例化,但它可能正在使用一些共享资源)。只要您在开发环境中测试您的应用程序,它的行为似乎与预期一致,但一旦您将其投入生产,您就会遇到问题。这表明您可能遇到应用程序池问题

IIS Web 应用程序池功能实际上HttpApplication为您的应用程序实例化了多个实例,它们可能都共享公共的一次性资源。如果您的一次性对象就是这种情况并且您正在共享它,那么它可能不是线程安全的。当您不将共享资源使用情况包装在线程安全操作中时,情况也是如此。

这就是为什么当一个请求正在进行时另一个请求开始并且第一个处理对象而第二个进程仍在使用它的原因。

更多信息总是有帮助的

如果您能解释一次性对象/资源的性质以及您如何在应用程序中使用它,我们可以为您提供更好的帮助。但与此同时,您可以阅读我的博客文章,其中讨论了应用程序池和处理它们。这与一次性物品本身无关,但您可能仍然会发现所有信息都非常有用和有帮助。

于 2012-10-19T08:54:24.947 回答
2

如果您需要在控制器内部使用一些可按请求处理的对象,我建议您使用控制器的生命周期处理程序,而不是使用 Application_BeginRequest 和 Application_EndRequest。请参阅以下示例。

控制器:

public class BaseController : Controller
{
    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        this.HttpContext.Items["MyDisposableObject"] = new MyDisposableObject();
    }

    protected override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        base.OnResultExecuted(filterContext);

        if (this.HttpContext.Items.Contains("MyDisposableObject"))
        {
            var myDisposableObject = 
                    this.HttpContext.Items["MyDisposableObject"] as IDisposable;

            if (myDisposableObject != null)
            {
                myDisposableObject.Dispose();
            }
        }
    }
}

IDisposable对象:

public sealed class MyDisposableObject : IDisposable
{
    private bool disposed;

    public void Dispose()
    {
        if (!this.disposed)
        {
            // Dispose all managed 
            // and unmanaged resources. 

            // Note disposing has been done.
            this.disposed = true;
        }
    }
}
于 2012-10-15T06:58:36.417 回答
0

如果对象的范围限定为控制器级别,您可以覆盖处理这些对象的Dispose方法。Controller

protected override void Dispose(bool disposing)
{
  if(disposing)
  {
    // dispose the objects here
  }

  base.Dispose(disposing);
}

如果您在应用程序中使用一些 DI 框架(如 Ninject),您可以将该工作委托给他们。

除了在请求结束时释放对象之外,您还可以尝试将它们包装在一个using语句中,无论您通过这种方式访问​​什么位置,都可以确保对象已被释放。

于 2012-10-15T15:45:19.743 回答