【问题标题】:Error opening excel generated with EPPlus in medium trust environment在中等信任环境中打开使用 EPPlus 生成的 Excel 时出错
【发布时间】:2016-08-04 23:59:46
【问题描述】:

我搜索了高低,发现类似的问题都有类似的答案,但似乎没有一个能解决我的问题。我的最终目标是允许用户将数据表保存到在 excel 中打开(不保存)的 excel 文档中,如果他们愿意,他们可以选择保存它。这可以通过单击用 c# 编写的网页上的按钮来完成。

有很多关于如何做到这一点的例子,有很多不同的方式,其中很多看起来很简单——我似乎无法找到一种在我所处的环境中完全有效的方法(中等信任的生产环境和这不能更改)。

本质上,当在网页上单击一个按钮时,我的代码会使用 EPPlus 创建一个 excel 文件:

ExcelPackage p = new ExcelPackage();
p.Workbook.Worksheets.Add(worksheetname);
ExcelWorksheet workSheet = p.Workbook.Worksheets[1];
workSheet.Cells[1,1].LoadFromDataTable(dt, true);
var range = workSheet.Cells[1,1,dt.Rows.Count,dt.Columns.Count];
var table = workSheet.Tables.Add(range, "results");
table.ShowTotal = false;
table.TableStyle = TableStyles.Medium4;
workSheet.Cells.AutoFitColumns();
workSheet.Cells.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
workSheet.View.ShowGridLines = false;
Response.Clear();
Response.ClearHeaders();
Response.BinaryWrite(p.GetAsByteArray());
//Also tried this instead of above line with same error: p.SaveAs(Response.OutputStream);
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;  filename=" + filename + ".xlsx");
Response.End();

这段代码看起来很简单,可以在我的机器上本地运行。我单击该按钮,然后收到保存或打开的提示。我选择打开,文件在 Excel 中打开,这正是我的最终用户想要的。然后我将网站复制到我们的开发网络服务器(完全信任),它仍然运行良好。然后我复制到我们的暂存环境,这是中等信任,而不是完全信任并得到以下错误:System.Security.SecurityException Exception Message: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

我不是要保存文件,只是简单地显示给最终用户以便能够在 Excel 中打开它。然后,他们可以根据需要选择从 Excel 应用中另存为。

使用 Excel 互操作执行此操作很简单,而且我也可以在本地运行它,但是如果服务器上没有 Excel,我不认为这是一个可行的选择。因此我决定尝试 EPPlus,这似乎是答案,直到它在我们的暂存环境中不起作用。我能想到的唯一区别是我们的暂存环境是中等信任,而开发环境是完全信任。我需要一个在中等信任下工作的解决方案,但没有我在下面使用 html 尝试的其他选项的错误。

我以前是用html做的,用下面的代码打开,但由于不是真正的excel文件,所以当用户选择打开时,总是报错:“文件格式和扩展名不匹配. 文件可能已损坏或不安全。除非您信任其来源,否则不要打开它。您仍然要打开它吗?"。他们可以直接点击“是”,大多数情况下文件会打开并且表现得很好,其他时候它只会说“无法读取文件”,他们将不得不重新点击按钮——他们已经要求这个错误消失。这是我过去的做法(同样,这在大多数情况下都有效,并且在我们的中等信任环境中工作得很好,但是有那个讨厌的错误)。这就是为什么我决定走创建一个“真正的”excel文件的路线——以避免这个错误。

System.IO.StringWriter tw = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(tw);
DataGrid dgGrid = new DataGrid();
dgGrid.DataSource = dt;
dgGrid.DataBind();
dgGrid.RenderControl(hw);
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.Buffer = true;
Response.Expires = 0;
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//Also tried these two ways to see if the "file format and extension don't match" error go away-it didn't
//also tried sending in filename with .xls and .xlsx extension with same results
//Response.ContentType = "application/vnd.ms-excel";
//Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename);
this.EnableViewState = false;
Response.Write(tw.ToString());
Response.Flush();
Response.Clear();
Response.End();

任何建议都会很棒!此外,如果有另一个开源工具可以完成这项工作,那也很好。我不能使用任何和所有的开源选项,但如果有人对另一个可以在中等信任下工作的工具提出建议,我可以看看它是否在我公司的批准列表中。

【问题讨论】:

  • 不太可能,但请检查一下以防万一ad-thomas.blogspot.com/2013/09/…
  • “填充工作表”这一步是否还涉及任何文件 IO?也许您正在从文件系统中读取一些内容来填充数据?
  • Eric,您提供的链接讨论了在服务器上授予 dll 额外权限,这在我公司的环境中不是一个选项。
  • 这是我最初用于填充工作表的代码。它不做任何文件 IO。我只是取一个填充了数据的数据表并将其传输到工作表:
  • @EricJ。抱歉,我不知道如何让我的代码在 cmets 中正确显示,所以我修改了我原来的帖子

标签: c# export-to-excel epplus


【解决方案1】:

问题在于 EPPlus 正在使用 System.IO 中的功能,即使在使用获取内存流的构造函数时也是如此。该特定库需要完全信任,因此它不会在中等信任环境中运行。看看以下两个文件:

http://epplus.codeplex.com/SourceControl/latest#EPPlus/Packaging/ZipPackage.cs

string name = Path.GetFileName(p.Key);
string extension = Path.GetExtension(p.Key);

http://epplus.codeplex.com/SourceControl/latest#EPPlus/Packaging/ZipPackagePart.cs

internal void WriteZip(ZipOutputStream os)
{
    ...code...
    if (_rels.Count > 0)
    {
        string f = Uri.OriginalString;
        var name = Path.GetFileName(f);
        _rels.WriteZip(os, (string.Format("{0}_rels/{1}.rels", f.Substring(0, f.Length - name.Length), name)));
    }
    ...code...
}

这两个部分都使用 System.IO 中的 Path 类来执行一些基本任务。

ZipPackage.cs 解决方案:

var parts = p.Key.Split('/');
var name = parts[parts.Length - 1];
parts = name.Split('.');
var extension = "." + parts[parts.Length - 1];

ZipPackagePart.cs 解决方案:

internal void WriteZip(ZipOutputStream os)
{
    ...code...
    if (_rels.Count > 0)
    {
        string f = Uri.OriginalString;
        var parts = f.Split('/');
        var name = parts[parts.Length - 1];
        _rels.WriteZip(os, (string.Format("{0}_rels/{1}.rels", f.Substring(0, f.Length - name.Length), name)));
    }
    ...code...
}

这个问题可能会在其他地方出现,但这应该让您了解在将源代码引入解决方案后需要查找和更改的内容。祝你好运!

【讨论】:

  • 感谢您提供的信息,但我仍然不知道要更改哪些位才能使其正常工作,所以我最终选择了另一个可以在 Medium Trust 中开箱即用的软件包,非营利组织。工作原理与 EPPlus 几乎相同,但没有那么优雅,但是嘿,它无需修改源代码即可工作。如果我真的对不使用 EPPlus 感到困扰的话,也许我以后会再来一次。
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多