在用户的下载文件夹中保存 excel 文件产生错误(.NET Core Razor Pages)

Saving excel file in user's downloads folder producing error (.NET Core Razor Pages)

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

下面的代码在本地主机上运行良好 - 我点击按钮,它保存到我的下载文件夹,我可以查看它。

但是,在我发布并尝试后,我收到一条错误消息,指出 "Could not find a part of the path 'C:\WINDOWS\system32\config\systemprofile\Downloads\PartCommentHistory.xlsx'."。

我也完全可以更改此代码,而不是拉出保存文件对话框 window 并允许用户首先选择文件的保存位置 - 但我不确定如何. Google 没有太大帮助,所以我们来了!

如果我实际导航到此路径,我会注意到没有 Downloads 文件夹。我尝试在我的代码中添加一个 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);
        }

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

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

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

例如

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

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

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

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

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);
    }
}