3

我们有一个 Web 应用程序,可以生成 Excel 电子表格并在服务器端运行宏。然后它通过电子邮件将它们发送给不同的人。它是我们正在过渡但仍支持我们作为 IIS 中的网站交付的新应用程序的旧报告样式的一部分。

我知道执行 Office 自动化是一种不好的做法,因为我从 Microsoft 看到了不支持此功能的信息。此处的答案中也指出了打开 excel 错误: System.Runtime.InteropServices.COMException (0x80080005): Retrieving the COM class factory for component with CLSID

无论如何,为了简短起见,excel 报告是在批处理场景中生成的,可以生成 3 到 300 个发送给不同人的报告。报告生成工作正常,直到它达到第 15 到第 20 个项目然后它就崩溃了,它给了我下面的错误

System.Runtime.InteropServices.COMException (0x80080005): Retrieving the COM class factory for component with CLSID {00024500-0000-0000-C000-000000000046} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
   at System.Runtime.Remoting.RemotingServices.AllocateUninitializedObject(RuntimeType objectType)
   at System.Runtime.Remoting.Activation.ActivationServices.CreateInstance(RuntimeType serverType)
   at System.Runtime.Remoting.Activation.ActivationServices.IsCurrentContextOK(RuntimeType serverType, Object[] props, Boolean bNewObj)
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at Ci.Infrastructure.Reporting.ReportProviderExcel.RunReport()

可能有什么问题?第一份报告成功了,我知道它不是 excel 模板,因为当我再次重新运行它时,所有失败的报告都会成功继续,当生成第 15 到第 20 份报告时,它会再次抛出错误。

更新:我们知道是在自找麻烦,但我需要一个解决方案来解决这个问题。请记住,这是针对我们将来会停止支持的遗留内容,但在过渡期间我们需要它工作。

我们尝试了序列化仍然不起作用。我们尝试在遇到 COM 异常时使生成 excel 报告的线程休眠,它可以工作,但这不是一个优雅的结果。任何解决此问题的好的解决方案都将获得赏金。

另一个更新:

通过在 finally 块上执行此操作解决

finally
{
    if (dataWorksheet != null)
    {
        Marshal.ReleaseComObject(dataWorksheet);
    }

    if (worksheets != null)
    {
        Marshal.ReleaseComObject(worksheets);
    }

    if (workbook != null)
    {
        workbook.Close(false);
        Marshal.ReleaseComObject(workbook);
    }

    if (workbooks != null)
    {
        workbooks.Close();
        Marshal.ReleaseComObject(workbooks);
    }

    if (excel != null)
    {
        excel.Quit();
        Marshal.ReleaseComObject(excel);
    }
}

就像 MarkWalls 所说的那样,关闭每个 excel 实例作为一个工作单元,在再次使用之前完全清除 EXCEL 进程。

4

4 回答 4

7

服务器执行失败

您没有进行太多研究,您应该始终查看 Windows 应用程序事件日志以获取有关此的更多详细信息。我只是假设您遇到了从 .NET 程序中使用 Excel 的典型问题。

这个错误描述总是准确的,COM 根本无法启动 Excel.exe。这几乎总是因为操作完全耗尽资源,内核内存池通常是用完的。您通常可以通过启动任务管理器来了解原因(希望它仍然有效),然后查看“进程”选项卡。您很有可能会看到数十个 Excel.exe 副本正在运行。如果您无法启动任务管理器,请在重新启动应用程序时留意列表。

Excel 是一个“胖”进程,它使用许多操作系统资源。它实际上是为桌面使用而编写的,只有一个 Excel.exe 实例会运行。即使您再次启动它,第二个实例也会启动并注意到另一个实例已经在运行。它与第一个对话并要求它做你想做的事情,比如打开另一个文档。然后退出,只留下第一个运行。当您使用 COM 时,同样的机制不存在。不是没有你自己照顾它,只创建一个实例并让它完成所有工作。

当您停止使用这些 Excel.exe 实例时,它们没有退出是有充分理由的。您的程序中的垃圾收集存在问题。收集器运行得不够频繁。很容易陷入这种麻烦,您通常会让 Excel 完成所有繁重的工作,并且您自己永远不会分配足够的对象来让垃圾收集器运行。

这很麻烦,Excel 只能在其接口实例被垃圾收集时退出。COM 互操作场景中的内存管理非常不同,它是引用计数的。当你开始使用一个接口,比如应用程序,那么引用计数就会增加。当终结器运行时它会下降。直到垃圾收集之后才会发生这种情况。

许多程序员通过调用 Marshal.ReleaseComObject() 来强制降低引用计数来解决这个问题。许多程序员也遇到了这个问题,除非你为每个接口引用调用它,否则它不会工作。是否有一些在程序中不可见。

最好的方法是在使用 Excel 后强制触发垃圾回收。将任何接口引用设置为 null 并调用 GC.Collect() + GC.WaitForPendingFinalizers()。请务必在没有附加调试器的情况下测试发布版本。并确保在与使用 Excel 接口的方法不同的方法中执行此操作。任务管理器会告诉您是否领先。

在服务器上运行 Excel 仍然不是一个好主意,但如果这种方法对您有效,那么您将有一些喘息的空间。

于 2013-05-06T00:06:50.567 回答
5

我有一个很像这样的问题。上面的答案是正确的——你可能基本上有一个非垃圾收集的 excel 实例池在服务器上。

我的解决方案是非常小心地打开-创建-关闭每个 excel 实例作为一个工作单元,然后检查是否有任何 excel 实例保留在服务器进程中。它只是像晚上那样一个接一个地检查它们,然后将它们放在存储库中以在早上发送出去。

我们尝试过但最终没有使用的另一个想法是创建 CSV 文件而不是 excel 文件。如果您只需要数据,那么 CSV 会更轻量级。我们的工作簿中也有复杂的公式,没有这些公式就无法完成。

于 2013-05-06T16:04:23.170 回答
2

你真是自找麻烦。看看这是否有帮助:http: //blogs.msdn.com/b/adioltean/archive/2005/06/24/432519.aspx

于 2013-05-02T06:33:28.463 回答
0

您可以通过使用 ASP.NET、MSMQ 和 Windows 服务的异步编程来实现您的解决方案,以实现报表生成等长时间运行的流程

由于基于 Web 的体系结构需要持续的进程/线程执行,这就是为什么在具有生成大量报告的报告功能时经常发生系统故障的原因。

看看下面的这篇文章,我希望它对你有用。

http://www.codeproject.com/Articles/8809/How-to-do-asynchronous-programming-using-ASP-NET-M

问候沙兹

于 2013-05-08T14:08:59.277 回答