C# Error: Microsoft Excel cannot access the file '...'. There are several possible reasons

C# Error: Microsoft Excel cannot access the file '...'. There are several possible reasons

我开发了一个 ASP.Net MVC 应用程序,即在 IIS 服务器上 运行。我写了一个代码来读取 CSV 并将它的行插入到数据库中。

[HttpPost]
    public ActionResult InsertPosition(int id, HttpPostedFileBase position)
    {
        var posicoesExistentes = db.tbPositions.Where(s => s.id_unique == id).AsEnumerable();

        foreach (tbPosition posicao in posicoesExistentes)
        {
            db.tbPositions.Remove(posicao);
        }

        if (!Directory.Exists(Server.MapPath("~/App_Data/")))
        {
            System.IO.Directory.CreateDirectory(Server.MapPath("~/App_Data/"));
        }

        string excelPath = Server.MapPath("~/App_Data/" + position.FileName);
        if (System.IO.File.Exists(excelPath))
        {
            System.IO.File.Delete(excelPath);
        }

        position.SaveAs(excelPath);

        string tempPath = Server.MapPath("~/App_Data/" + "tmp_" + position.FileName);
        System.IO.File.Copy(excelPath, tempPath, true);

        Excel.Application application = new Excel.Application();
        Excel.Workbook workbook = application.Workbooks.Open(tempPath, ReadOnly: true,Editable:false);
        Excel.Worksheet worksheet = workbook.ActiveSheet;
        Excel.Range range = worksheet.UsedRange;
        application.Visible = true;

        for (int row = 1; row < range.Rows.Count - 1; row++)
        {
            tbPosition p = new tbPosition();

            p.position = (((Excel.Range)range.Cells[row, 1]).Text == "") ? null : Convert.ToInt32(((Excel.Range)range.Cells[row, 1]).Text);
            p.left = ((Excel.Range)range.Cells[row, 2]).Text;
            p.right = ((Excel.Range)range.Cells[row, 3]).Text;
            p.paper = ((Excel.Range)range.Cells[row, 4]).Text;
            p.denomination = ((Excel.Range)range.Cells[row, 5]).Text;
            p.material = ((Excel.Range)range.Cells[row, 6]).Text;
            p.norme = ((Excel.Range)range.Cells[row, 7]).Text;
            p.finalized_measures = ((Excel.Range)range.Cells[row, 8]).Text;
            p.observation = ((Excel.Range)range.Cells[row, 9]).Text;
            p.id_unique = id;

            db.tbPositions.Add(p);
            db.SaveChanges();
        }
        workbook.Close(true, Type.Missing, Type.Missing);
        application.Quit();
        System.IO.File.Delete(tempPath);

        return Json("Success", JsonRequestBehavior.AllowGet);
    }

但在 return 中我收到错误消息“Microsoft Excel 无法访问文件“...”。当我尝试打开请求的 excel 文件时,可能有多种原因。

我已经尝试以只读方式打开文件,我已经尝试授予对指定文件夹的权限,多种关闭 excel 文件的方法,并创建原始文件的副本并阅读他。但是这些解决方案中的每一个都不成功。我在这里错过了什么?

不支持

简短的回答是,在 UI 上下文之外不支持尝试使用自动化 API 以编程方式操作 Excel 文档。您 遇到各种挫折(例如,允许 API 显示对话框 - 如果 "OK" 是 运行 在网络服务器上?)。

微软明确地state this here

Microsoft does not recommend or support server-side Automation of Office.

那我用什么?

我建议使用 OpenXML SDK - 这是免费的,完全支持并且比自动化 API 快得多。

Aspose也有一套产品,不过不是免费的,我没用过

但我必须这样做

但是,如果您绝对必须使用 COM API,那么以下内容可能会对您有所帮助:

这里有龙

Excel 中自动化的最大问题是您需要确保在使用它们时关闭每个引用(通过对其调用 ReleaseComObject)。

例如,以下代码将导致 Excel 保持打开状态:

var range;
range = excelApplication.Range("A1");
range = excelApplication.Range("A2");
System.Runtime.InteropServices.Marshal.ReleaseComObject(range)
range = Nothing

这是因为在获取范围 "A1" 的调用中还遗留了一个引用。

因此,我建议围绕 Excel class 编写一个包装器,以便任何访问,例如,一个范围在访问新范围之前释放任何先前访问的范围。

作为参考,这里是我在 class 中用来释放 COM 对象的代码 我写的:

Private Sub ReleaseComObject(ByVal o As Object)
    Try
        If Not IsNothing(o) Then
            While System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0
                'Wait for COM object to be released.'
            End While
        End If
        o = Nothing
    Catch exc As System.Runtime.InteropServices.COMException
        LogError(exc) ' Suppress errors thrown here '
    End Try
End Sub

试试这个

  protected void ImportCSV(object sender, EventArgs e)
        {
            importbtn();

        }
        public class Item
        {
            public Item(string line)
            {
                var split = line.Split(',');
                string FIELD1 = split[0];
                string FIELD2 = split[1];
                string FIELD3 = split[2];


                string mainconn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;

                using (SqlConnection con = new SqlConnection(mainconn))
                {
                    using (SqlCommand cmd = new SqlCommand("storedProcedureName", con))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;


                        cmd.Parameters.AddWithValue("@FIELD1", SqlDbType.VarChar).Value = FIELD1;
                        cmd.Parameters.AddWithValue("@FIELD2", SqlDbType.VarChar).Value = FIELD2;
                        cmd.Parameters.AddWithValue("@FIELD3", SqlDbType.VarChar).Value = FIELD3;

                        con.Open();
                        cmd.ExecuteNonQuery();
                    }


                }

            }
        }
        private void importbtn()
        {
            try
            {

                string csvPath = Server.MapPath("~/Files/") + Path.GetFileName(FileUpload1.PostedFile.FileName);
                FileUpload1.SaveAs(csvPath);


                var listOfObjects = File.ReadLines(csvPath).Select(line => new Item(line)).ToList();


                DataTable dt = new DataTable();

                dt.Columns.AddRange(new DataColumn[3] { new DataColumn("FIELD1", typeof(string)),
                new DataColumn("FIELD2", typeof(string)),
                new DataColumn("FIELD3",typeof(string)) });


                string csvData = File.ReadAllText(csvPath);


                foreach (string row in csvData.Split('\n'))
                {

                    if (!string.IsNullOrEmpty(row))
                    {


                        dt.Rows.Add();

                        int i = 0;

                        //Execute a loop over the columns.
                        foreach (string cell in row.Split(','))
                        {


                            dt.Rows[dt.Rows.Count - 1][i] = cell;

                            i++;

                        }

                    }
                }

                GridView1.DataSource = dt;
                GridView1.DataBind();


                Label1.Text = "File Attached Successfully";



            }
            catch (Exception ex)
            {
                Message.Text = "Please Attach any File" /*+ ex.Message*/;

            }
        }