【问题标题】:Saving excel file in user's downloads folder producing error (.NET Core Razor Pages)将 excel 文件保存在用户的下载文件夹中会产生错误(.NET Core Razor 页面)
【发布时间】:2019-07-19 19:29:03
【问题描述】:

在我的 razor 页面应用程序中,我有一个按钮,您可以单击该按钮创建一个 excel 文件并自动将其保存到您的下载文件夹中。

下面的代码在 localhost 中运行良好 - 我单击按钮,它会保存到我的下载文件夹中,我可以查看它。

但是,一旦我发布并尝试,我收到一条错误消息,指出“找不到路径 'C:\WINDOWS\system32\config\systemprofile\Downloads\PartCommentHistory.xlsx' 的一部分。”。

我也可以更改此代码以打开保存文件对话框窗口并允许用户首先选择文件的保存位置 - 但我不确定如何。 Google 帮不上什么忙,所以我们来了!

如果我实际导航到此路径,我注意到没有下载文件夹。我尝试在我的代码中添加一个 if 语句,说明如果 Downloads 文件夹在此处不存在,请先创建它,然后将文件保存在那里。但是,这会产生另一个错误,即我无权访问该路径。

public async Task<IActionResult> OnPostExportAsync(string currentFilter)
        {
            string sFilePath = Path.Combine(Environment.ExpandEnvironmentVariables("%USERPROFILE%"),"Downloads");
            string sFileName = @"PartCommentHistory.xlsx";
            string URL = string.Format("{0}://{1}/{2}", Request.Scheme, Request.Host, sFileName);
            FileInfo file = new FileInfo(Path.Combine(sFilePath, sFileName));
            var memory = new MemoryStream();
            using (var fs = new FileStream(Path.Combine(sFilePath, sFileName), FileMode.Create, FileAccess.Write))
            {
                ExcelPackage pck = new ExcelPackage();
                ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Worksheet1");

                List<CmtPartComment> commentlist = _context.CmtPartComments.Select(x => new CmtPartComment
                {
                    SupplierNo = x.SupplierNo,
                    PartNo = x.PartNo,
                    Comment = x.Comment,
                    EnterBy = x.EnterBy,
                    EnteredDt = x.EnterDt.ToString("yyyy-MM-dd HH:mm:ss tt"),
                    CompletedDt = x.CompleteDt.ToString("yyyy-MM-dd HH:mm:ss tt")
                }).Include(c => c.System).OrderByDescending(x => x.EnterDt).Where(x => x.PartNo == currentFilter).ToList();

                ws.Cells[1, 1].Value = "SupplierNo";
                ws.Cells[1, 2].Value = "PartNo";
                ws.Cells[1, 3].Value = "Comment";
                ws.Cells[1, 4].Value = "EnterBy";
                ws.Cells[1, 5].Value = "EnterDt";
                ws.Cells[1, 6].Value = "CompleteDt";

                int recordIndex = 2;
                foreach (var item in commentlist)
                {
                    ws.Cells[recordIndex, 1].Value = item.SupplierNo;
                    ws.Cells[recordIndex, 2].Value = item.PartNo;
                    ws.Cells[recordIndex, 3].Value = item.Comment;
                    ws.Cells[recordIndex, 4].Value = item.EnterBy;
                    ws.Cells[recordIndex, 5].Value = item.EnteredDt;
                    ws.Cells[recordIndex, 6].Value = item.CompletedDt;
                    recordIndex++;
                }

                ws.Cells["A:AZ"].AutoFitColumns();

                pck.SaveAs(fs);
            }

            using (var stream = new FileStream(Path.Combine(sFilePath, sFileName), FileMode.Open))
            {
                await stream.CopyToAsync(memory);
            }
            memory.Position = 0;
            return File(memory, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", sFileName);
        }

【问题讨论】:

  • 为什么要保存到 'C:\WINDOWS\system32\....' ?我希望 'C:\Users\username\downloads\..."
  • 您的代码正在运行 server 端。当您解析 %USERPROFILE%\Downloads 时,这是根据 server (具体来说,是执行代码的服务器上的用户)并且与 client 保存的位置无关下载。它在localhost 上工作表明您正在以与登录Windows 相同的用户身份运行Web 服务器,因此,该用户的Downloads 目录与您的Downloads 目录相同(因为它们是同一用户)。
  • sFilePath确切值是多少?
  • 我认为 @JazzmanJim %USERPROFILE% 正在生成该路径。
  • @mjwills 来自错误消息:C:\WINDOWS\system32\config\systemprofile\Downloads\

标签: c# asp.net-core filestream razor-pages


【解决方案1】:

对于您的问题,这是由于您正在通过using (var fs = new FileStream(Path.Combine(sFilePath, sFileName), FileMode.Create, FileAccess.Write))在服务器端创建一个临时文件,该文件可能在服务器端不存在。

根据您的要求,您正在尝试创建一个文件并将其返回给客户端。如果是这样,则无需在服务器端创建本地文件,您可以返回文件的字节,如下所示:

public async Task<IActionResult> OnPostExportByInMemoryAsync(string currentFilter)
{
    string sFileName = @"PartCommentHistory.xlsx";

    using (var pck = new ExcelPackage())
    {
        ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Worksheet1");
        ws.Cells[1, 1].Value = "SupplierNo";
        ws.Cells[1, 2].Value = "PartNo";
        ws.Cells[1, 3].Value = "Comment";
        ws.Cells[1, 4].Value = "EnterBy";
        ws.Cells[1, 5].Value = "EnterDt";
        ws.Cells[1, 6].Value = "CompleteDt";
        ws.Cells["A:AZ"].AutoFitColumns();
        return File(pck.GetAsByteArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", sFileName);
    }
}

【讨论】:

  • 这成功了!感谢您的回复并解释了我使用服务器端的混淆。
【解决方案2】:

使用此方法获取文件夹路径

    Environment.GetFolderPath(Environment.SpecialFolder.Yourspecialfoldernamehere, System.Environment.SpecialFolderOption.None)

例如

    Environment.GetFolderPath(Environment.SpecialFolder.System));

在上面的例子中系统是一个特殊的文件夹。

【讨论】:

    【解决方案3】:

    您无法确定文件可以保存在客户端计算机的哪个位置。它似乎在您的机器上工作的唯一原因是因为您的机器充当服务器。你所能做的就是在用户下载文件时强制一个保存或打开对话框,这是通过将内容类型设置为application/octet-stream来实现的: Do I need Content-Type: application/octet-stream for file download?

    【讨论】:

    • 如果您处于运行 Web 应用程序的用户对您尝试保存到客户端计算机上的文件夹具有写访问权限的环境中(如在,它们在同一个网络上,并且您的 IIS 站点具有太强大的权限)。然后它可以保存它,但你完全绕过了 HTTP 协议来这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多