我正在使用以下代码在ASP.net表单上动态写入excel文件,该表单可以将数据表保存为excel。
//Create Excel Object
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook workbook = excel.Workbooks.Open(target);
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1];
worksheet.Name = "Worksheet1";
excel.Visible = false;
//Generate Fields Name
foreach (DataColumn col in dataTable.Columns)
{
colIndex++;
excel.Cells[1, colIndex] = col.ColumnName;
}
object[,] objData = new object[rowNo, columnNo];
for (int row = 0; row < rowNo; row++)
{
for (int col = 0; col < columnNo; col++)
{
objData[row, col] = dataTable.Rows[row][col];
}
}
Microsoft.Office.Interop.Excel.Range range;
range = worksheet.Range[excel.Cells[2, 1], excel.Cells[rowNo + 1, columnNo]];
range.Value2 = objData;
worksheet.Columns.AutoFit();
workbook.Save();
workbook.Close();
IntPtr hwnd = new IntPtr(excel.Hwnd);
IntPtr processId;
IntPtr foo = GetWindowThreadProcessId(hwnd, out processId);
Process proc = Process.GetProcessById(processId.ToInt32());
proc.Kill();
//excel.Quit();
GC.Collect();
GC.WaitForPendingFinalizers();
将数据写入excel文件。但是,当我尝试使用上面的proc.Kill()来杀死进程时,我得到以下异常
描述:执行当前Web请求期间发生了未处理的异常。请查看堆栈跟踪,以获取有关错误及其在代码中的起源位置的更多信息。
异常详细信息:System.ComponentModel.Win32Exception:拒绝访问
来源错误:
在执行当前Web请求期间生成了未处理的异常。可以使用下面的异常堆栈跟踪来识别有关异常的起源和位置的信息。
堆栈追踪:
[Win32Exception (0x80004005): Access is denied]
System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) +1985316
System.Diagnostics.Process.Kill() +49
Faculty_Report1.FetchData_EXCEL(String prog, String cls, String spcln, String fromdate, String todate) +2413
Faculty_Report1.fetchselectedvalues_EXCEL() +1044
System.Web.UI.WebControls.ImageButton.OnClick(ImageClickEventArgs e) +187
System.Web.UI.WebControls.ImageButton.RaisePostBackEvent(String eventArgument) +165
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3707
我没有使用proc.Kill()方法,而是尝试使用excel.Quit()方法,但该过程不会终止。当我这样做时,每次用户尝试生成报告时,我都会使用新的Excel流程。
我在web.config文件中有用户模拟,但这不会改变任何内容。
<system.web>
<identity impersonate="true" userName="xxxxxx" password="xxxxxxxx" />
</system.web>
关于如何避免异常并确保excel进程终止正常的任何指示?我已经尝试了我在这里找到的COM清理解决方案,但它不起作用..
答案 0 :(得分:5)
MS不支持在服务器上使用Interop(如ASP.NET) - 请参阅http://support.microsoft.com/default.aspx?scid=kb;EN-US;q257757#kb2
由于Windows Vista MS引入了一些与安全相关的措施,这些措施阻止Windows服务执行“类似桌面”的操作......这意味着您必须绕过一些安全措施才能使其工作(不推荐!)。
要在服务器场景中处理Excel,有几个选项(免费和商业):
我可以推荐Aspose.Cells和Flexcel ...没试过SpreadsheetGear但是听到+读了很多关于它的好东西......
免费选项(仅适用于较新的xlsx格式!)例如OpenXML 2 from MS和EPPlus。
答案 1 :(得分:1)
要创建简单的Excel数据表,除了互操作之外还有一些可能有趣的选项,但是有些方法可以在必须使用互操作时帮助excel。
首先是第一件事。如果您确定可以重用现有应用程序,可以使用'oldschool'getactiveobject来获取现有实例:
using System.Runtime.InteropServices;
Microsoft.Office.Interop.Excel.Application excel;
try
{
excel = (Microsoft.Office.Interop.Excel)Marshal.GetActiveObject("Excel.Application");
}
catch
{
excel = new Microsoft.Office.Interop.Excel.Application();
}
要成功退出excel应用程序,必须销毁所有句柄,但我想这就是你清理COM的意思吗? 确保所有句柄都与marshal.releasecomobject一起发布(或许在现代互操作中不再需要它)可能是一种痛苦,这就是为什么我将每个办公室互操作'句柄'包括在工作表,工作簿,范围等中的原因。包装。 我所拥有的代码没有多大用处,但我会在这里发布它以提出一个大致的想法:
public class WrapperBase<T>: IWrapper
{
protected T obj;
protected internal WrapperBase(IWrapper Owner)
{
SetOwner(Owner);
}
protected WrapperBase() { }
CultureSwitcher cultswitch;
public CultureSwitcher CultureSwitcher
{
get
{
if (cultswitch == null)
{
if (owner != null) return owner.CultureSwitcher;
cultswitch = new CultureSwitcher();
}
return cultswitch;
}
}
public T Object { get { return obj; } internal set { obj = value; } }
//public abstract void Save();
public bool IsDisposed { get { return disposed; } }
bool disposed;
public void Dispose()
{
Dispose(false);
}
void Dispose(bool fromfinalize)
{
if (disposed) return;
disposed = true;
if (!fromfinalize)
GC.SuppressFinalize(this);
CultureSwitcher.Try(OnDisposing);
if (obj != null)
{
while (Marshal.ReleaseComObject(obj) > 0) { }
obj = default(T);
}
if (cultswitch != null)
{
cultswitch.Dispose();
cultswitch = null;
}
SetOwner(null);
}
protected virtual void OnDisposing()
{
if (children != null)
{
foreach (var c in children)
c.Dispose();
children = null;
}
}
~WrapperBase()
{
Dispose(true);
}
List<IWrapper> children;
IWrapper owner;
public IWrapper Owner
{
get { return owner; }
}
protected void SetOwner(IWrapper Owner)
{
if (Owner == owner) return;
if (owner != null)
{
owner.DeRegister(this);
}
owner = Owner;
if (owner != null)
{
owner.Register(this);
}
}
public void Register(IWrapper Child)
{
if (disposed)
throw new ObjectDisposedException("Cannot register children after disposing");
if (children == null)
children = new List<IWrapper>();
children.Add(Child);
}
public void DeRegister(IWrapper Child)
{
if (disposed) return;
children.Remove(Child);
}
protected IEnumerable<IWrapper> GetChildren()
{
return children;
}
}
答案 2 :(得分:0)
我在过去使用Interop使Excel应用程序真正关闭时也遇到了问题,但是发现解决方案是释放应用程序的实例。请尝试以下方法:
excel.Quit();
excel = null;
这听起来太简单了,但它成功地阻止了Excel的ghost实例在我的应用程序中停留在操作系统中。