在服务器端生成的Excel中获取System.Runtime.InteropServices.COMException错误

Ray*_*und 3 .net c# com ms-office office-automation

我们有一个Web应用程序,可以生成excel电子表格并在服务器端运行宏.然后通过电子邮件将它们发送给不同的人.它是我们正在转换的遗留报告风格的一部分,但仍然支持我们作为IIS中的网站提供的新应用程序.

我知道办公自动化是一种不好的做法,因为我看到微软的信息不支持.这里的答案也表明打开excel错误:System.Runtime.InteropServices.COMException(0x80080005):使用CLSID检索组件的COM类工厂

无论如何缩短故事,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()
Run Code Online (Sandbox Code Playgroud)

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

更新:我们知道有问题,但我需要一个解决方案来解决问题.请记住,这是遗留的东西,我们将来会停止支持,但在过渡期我们需要它才能工作.

我们尝试序列化仍然无法正常工作.我们试图在生成excel报告时遇到COM异常,但它可以工作,但这不是一个优雅的结果.解决这个问题的任何好方法都将获得赏金.

另一个更新:

通过在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Han*_*ant 7

服务器执行失败

您没有展示太多研究,您应该始终查看Windows应用程序事件日志以获取有关此内容的更多详细信息.我只是假设您正在使用.NET程序中使用Excel的典型问题.

此错误描述始终准确,COM可以从字面上不启动Excel.exe.这几乎总是因为操作是资源不足,内核内存池通常是用完的.您通常可以通过启动任务管理器(希望它仍然有效)来查看原因,并查看"进程"选项卡.很有可能你会看到几十份Excel.exe正在运行.如果您无法启动任务管理器,请在重新启动应用程序时密切关注列表.

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

这些Excel.exe实例在您停止使用它们时不会退出的原因很充分.您的程序中存在垃圾回收问题.收集器运行不够频繁.很容易遇到这种麻烦,你通常会让Excel完成所有繁重工作,而不是自己分配足够的对象来让垃圾收集器运行.

这意味着麻烦,Excel只能在其接口实例被垃圾收集时退出.内存管理在COM互操作方案中非常不同,它是引用计数.当您开始使用接口(如Application)时,引用计数会增加.当终结器运行时它会下降.直到垃圾收集后才会发生这种情况.

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

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

在服务器上运行Excel仍然是一个坏主意,但如果这种方法适合你,那么你将有一些喘息空间.


Mar*_*lls 5

我有一个像这样的问题.上面的答案是正确的 - 你可能基本上有一个非垃圾收集的excel实例池弄糟了服务器.

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

另一个我们尝试但最后不得不使用的想法是创建CSV文件而不是excel文件.如果您只需要数据,那么CSV更轻巧.我们在工作簿中也有复杂的公式,这是不可能的.