我有一些简单的类需要在请求结束时处理。
为此,我在Dispose
中的Application_EndRequest
事件中对这些对象调用Global.asax
方法。
这“在我的机器上工作正常”但在我的生产服务器上导致一些问题Cannot access a disposed object.
这种情况发生在一些MVC助手中。
在我看来,Application_EndRequest在请求结束时被触发。这不是这种情况吗?我应该用另一个事件处理我的物品吗?
答案 0 :(得分:5)
我怀疑你的一次性对象没有绑定请求,而是app wide(它可以根据请求进行实例化,但可能使用了一些共享资源)。只要您在开发环境中测试应用程序,它似乎就像预期的那样行事,但只要您将其投入生产就会出现问题。 这表示您可能遇到应用程序池问题。
IIS Web应用程序池功能实际上为您的应用程序实例化多个HttpApplication
实例,并且它们可能共享公共可用资源。如果您的一次性物品就是这种情况并且您正在共享它,则可能是它不是线程安全的。如果不将共享资源使用包装在线程安全操作中,情况也是如此。
这就是为什么当一个请求正在进行时,另一个请求开始,第一个处理该对象,而第二个进程仍在使用它时,可能会发生这种情况。
如果您要解释一次性物品/资源的性质以及您在应用程序中如何使用它,我们可以更好地帮助您。但与此同时,您可以 read my blog post 讨论应用程序池并处理它们。这不是关于一次性物品本身,但您仍然可以发现所有信息都非常有用和有用。
答案 1 :(得分: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;
}
}
}
答案 2 :(得分:0)
如果对象的范围限定为控制器级别,则可以覆盖Dispose
Controller
方法来处置这些对象。
protected override void Dispose(bool disposing)
{
if(disposing)
{
// dispose the objects here
}
base.Dispose(disposing);
}
如果您在应用程序中使用某些DI框架(如Ninject),则可以将该作业委派给他们。
除了在请求的末尾处理对象,您还可以尝试将它们包装在using
语句中,只要您通过这种方式访问它,就可以确保对象处理完毕。