【问题标题】:ObjectDisposedException was unhandled: Safe handle has been closed at program endObjectDisposedException 未处理:安全句柄已在程序结束时关闭
【发布时间】:2011-10-27 14:50:19
【问题描述】:

我有一个 .NET 4 C# 控制台应用程序。它从我们的 IBM i 中提取数据并将其发送到我们的互联网 SQL Server。它工作完美,直到结束,我收到以下错误:

System.ObjectDisposedException 未处理 Message=安全句柄有 已关闭 Source=mscorlib ObjectName="" StackTrace: 在 System.Runtime.InteropServices.SafeHandle.DangerousRelease() 在 System.Threading.RegisteredWaitHandleSafe.Finalize() InnerException:

我的程序代码是:

class Program
{
    static void Main(string[] args)
    {
        System.Console.WriteLine("Begin: " + DateTime.Now.ToString());
        SystemCodeController sc = new SystemCodeController();
        sc.SyncSystemCodes();
        ParkingTicketController pt = new ParkingTicketController();
        pt.SyncParkingTickets();
        EmailHelper.SendSuccessEmail();
        System.Console.WriteLine("End: " + DateTime.Now.ToString());
    }
}

在控制台中,我看到了开始时间和结束时间。所以我知道最后一行确实被执行了。我忘记或不做我应该做的事情是什么?

更新:Sync* 方法将数据从 IBM 提取到一个对象中,然后使用实体框架将记录插入到数据库中。

public void SyncParkingTickets()
{
    ptr.ClearTable();
    ptr.InsertNewCitation(ibmI.GetAllCitations());
    ptr.SaveChanges();
}

public void InsertNewCitation(IEnumerable<ParkingTicket> citations)
{
    foreach (ParkingTicket citation in citations)
    {
        InsertNewCitation(citation);
    }
}

public void InsertNewCitation(ParkingTicket citation)
{
    db.AddToParkingTickets(citation);
}

public IEnumerable<ParkingTicket> GetAllCitations()
{
    SystemCodeRepository scr = new SystemCodeRepository();

    //  Create SQL statement

    DataTable dt = new DataTable();
    using (iDB2Connection conn = new iDB2Connection(_connString))
    {
        using (iDB2Command cmd = new iDB2Command(sb.ToString(), conn))
        {
            conn.Open();
            using (iDB2DataAdapter da = new iDB2DataAdapter(cmd)) { da.Fill(dt); }
            conn.Close();
        }
    }

    #region Fill object from DataTable
    var citations = from i in dt.AsEnumerable()
                    select new ParkingTicket
                    {
                        // Fill object
                    };
    #endregion

    return citations;
}

所有方法的操作都与此类似。

【问题讨论】:

  • Sync* 系列调用有什么作用?我们能看到那个代码吗?我敢打赌它会泄露一个 WaitHandle。
  • 我不知道WaitHandle是什么,所以我可能只是间接使用它。
  • 我已经追踪到 IBM 驱动程序,我已经更新了我的答案以反映这一点和可能的修复。

标签: c# .net-4.0 console-application objectdisposedexception


【解决方案1】:

在使用 iDB2Connection 系列数据库访问方法时,有一点点Googling reveals some scattered reports 的相同错误。显然,IBM 依赖 .Net 1.1 处理 EventHandles,在迁移到 .Net 2.0 per this Connect article 时发生了变化。

似乎唯一的缓解办法是更新到最新版本的 IBM 驱动程序(如您所述,使用 5.3 的 S21917 服务包或 5.4 的 SI37892)。


您是否在SafeWaitHandle 上致电Close() 以获取WaitHandle

WaitHandle wh = ...;

wh.SafeWaitHandle.Close(); // will throw ObjectDisposedException

From MSDN:

当您为 SafeWaitHandle 属性分配新值时,将在收集前一个 SafeWaitHandle 对象时关闭前一个句柄。不要手动关闭句柄,因为这会在 SafeWaitHandle 尝试关闭句柄时导致 ObjectDisposedException。

【讨论】:

  • 哇,这是一个糟糕的实现。调用Dispose 方法导致ObjectDisposedException?!
  • @ordag:实际上 ObjectDisposedException 是从代码中抛出的,通常是在另一个依赖于已处理事件句柄的线程中!
  • 好的...我使用 5.4 而不是 5.3 进行客户端访问。无论如何,我正在下载最新的补丁。我有一种感觉,这只会将我们更快地推向最新版本的 iSeries Access。这是一个皮塔饼。所有项目都必须一次升级,因为您不能同时安装多个版本的驱动程序。
  • 升级到我的 iSeries Access V5R4 到 SI37892 似乎奏效了。有趣,我以为我在使用最新版本。
【解决方案2】:

你的类型是Disposable吗?尝试在退出应用程序之前处置所有一次性资源。

【讨论】:

  • 这是我发帖后的第一个想法。我确保我的代码都没有IDisposable。那没有帮助。我现在确保我触摸的每个对象都包含.Dispose()
  • @MikeWills:添加IDisposable 并不能神奇地解决SafeHandle 使用的问题。您需要查看您的代码以了解 SafeHandle 或其派生类的用法。可能一些与 WaitHandle 相关的代码有问题。
  • 就像我上面说的,我不知道'WaitHandle'是什么,所以我可能只是间接使用它
【解决方案3】:

我也有同样的情况。问题在于SafeHandle.ReleaseHandle 中的P/Invoke 调用会产生一些魔力并调用System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean&amp; success),它会在处理SafeHandle 后尝试对其进行处理。

这不是你自己的SafeHandle 实现,不是吗?否则,您可以尝试扩展 CriticalHandle

【讨论】:

  • 不,我没有做过类似的事情。这是一个已知的错误?如果有,是否有解决方法?我不想在现场实施时遇到问题。
  • 我有同样的错误(当然不同的应用程序)。但再看一遍后,我觉得我错了。请参阅上面的编辑。
猜你喜欢
  • 2014-01-09
  • 1970-01-01
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 2014-01-17
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多