在中等信任环境中打开使用EPPlus生成的Excel时出错

时间:2016-03-16 22:28:09

标签: c# export-to-excel epplus

我已经搜索了高低,并找到了类似的问题所有类似的答案,似乎没有解决我的问题。我的最终目标是允许用户将数据表保存到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();

这段代码看起来很简单,可以从我的机器本地运行。我单击按钮,然后收到保存或打开的提示。我选择Open,文件在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();

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

1 个答案:

答案 0 :(得分:0)

问题是即使使用带有内存流的构造函数,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...
}

可能还有其他地方出现此问题,但这可以让您了解在将源代码提取到解决方案后需要查找和更改的内容。祝你好运!